Sort on a String That May Contain a Number

Sorting Strings that contains number in Java

Try this comparator, which removes all non-digit characters then compares the remaining characters as numbers:

Collections.sort(strings, new Comparator<String>() {
public int compare(String o1, String o2) {
return extractInt(o1) - extractInt(o2);
}

int extractInt(String s) {
String num = s.replaceAll("\\D", "");
// return 0 if no digits found
return num.isEmpty() ? 0 : Integer.parseInt(num);
}
});

Here's a test:

public static void main(String[] args) throws IOException {
List<String> strings = Arrays.asList("room1.2", "foo1.1", "foo", "room2.3", "room100.999", "room10", "room.3");

Collections.sort(strings, new Comparator<String>() {
public int compare(String o1, String o2) {
return extractInt(o1) - extractInt(o2);
}

int extractInt(String s) {
String num = s.replaceAll("\\D", "");
// return 0 if no digits found
return num.isEmpty() ? 0 : Integer.parseInt(num);
}
});
System.out.println(strings);
}

Output:

[foo, room1, room2, room10, room100]

When the numbers are decimals (also demonstrating Java 8+ style):

public static void main(String[] args) {
List<String> strings = Arrays.asList("room1.2", "foo1.1", "room2.3", "room100.999", "room10", "room.3");
Collections.sort(strings, Comparator.comparing(Application::extractDouble));
System.out.println(strings);
}

static double extractDouble(String s) {
String num = s.replaceAll("[^\\d.]", "");
// return 0 if no digits found
return num.isEmpty() ? 0 : Double.parseDouble(num);
}

Result:

[foo, room.3, foo1.1, room1.2, room2.3, room10, room100.999]

Sort on a string that may contain a number

The Alphanum Algorithm

From the website

"People sort strings with numbers differently than software. Most sorting algorithms compare ASCII values, which produces an ordering that is inconsistent with human logic. Here's how to fix it."

Edit: Here's a link to the Java Comparator Implementation from that site.

How do I sort strings that contain numbers in Java

  public static void main(String[] args)
{
String string = "3 42 \n 11 \t 7 dsfss 365 \r 1";
String[] numbers = string.split("\\D+");
Arrays.sort(numbers, new Comparator<String>()
{
public int compare(String s1, String s2)
{
return Integer.valueOf(s1).compareTo(Integer.valueOf(s2));
}
});
System.out.println(Arrays.toString(numbers));
}

Sorting a list of strings that contains numbers and letters

you can do it by using Comparator. With split("-") will seperate a single string where "-" are found and return a String[]. And then with the help of Integer.parseInt(((String) o).split("-")[0])), it will convert the first splitted String item to Integer and the Comparator can sort the list accordingly.

TOP10_Players.sort(Comparator.comparing((Object o) -> Integer.parseInt(((String) o).split("-")[0])));

Output: [1-Username1, 3-Username3, 5-Username2]

For descending order:

TOP10_Players.sort(Comparator.comparing((Object o) -> Integer.parseInt(((String) o).split("-")[0])).reversed());

Output: [5-Username2, 3-Username3, 1-Username1]

Sorting array of strings that contain number

You can do something like that:

list.sort(Comparator.comparing(YourClass::removeNumbers).thenComparing(YourClass::keepNumbers));

These are two methods:

private static String removeNumbers(String s) {
return s.replaceAll("\\d", "");
}

private static Integer keepNumbers(String s) {
String number = s.replaceAll("\\D", "");
if (!number.isEmpty()) {
return Integer.parseInt(number);
}
return 0;
}

For following data:

List<String> list = new ArrayList<>();
list.add("TEXT-2");
list.add("TEST-6");
list.add("TEST-1");
list.add("109");
list.add("TE");
list.add("TESTT-0");
list.add("TES-100");

This is the sorting result:

[109, TE, TES-100, TEST-1, TEST-6, TESTT-0, TEXT-2]

Clever sorting (Sort strings that may or may not contain numbers)

Given the clarifications in comments, you can split each string by /(\d+)/g and sort by each element in the resulting string array. Treat even indices as strings, and odd indices as numbers:

const input = ['unit 11', 'unit 1', 'unit 2', 'apt 11', 'apt 1', 'apt 2', 'unit A', 'unit c', 'unit B', 'apt a', 'apt C', 'apt b'];
function customSort (a, b) { a = a.toUpperCase().split(/(\d+)/g); b = b.toUpperCase().split(/(\d+)/g);
const length = Math.min(a.length, b.length);
for (let i = 0; i < length; i++) { const cmp = (i % 2) ? a[i] - b[i] : -(a[i] < b[i]) || +(a[i] > b[i]);
if (cmp) return cmp; }
return a.length - b.length;}
console.log(input.sort(customSort));

How to correctly sort a string with a number inside?

Perhaps you are looking for human sorting (also known as natural sorting):

import re

def atoi(text):
return int(text) if text.isdigit() else text

def natural_keys(text):
'''
alist.sort(key=natural_keys) sorts in human order
http://nedbatchelder.com/blog/200712/human_sorting.html
(See Toothy's implementation in the comments)
'''
return [ atoi(c) for c in re.split(r'(\d+)', text) ]

alist=[
"something1",
"something12",
"something17",
"something2",
"something25",
"something29"]

alist.sort(key=natural_keys)
print(alist)

yields

['something1', 'something2', 'something12', 'something17', 'something25', 'something29']

PS. I've changed my answer to use Toothy's implementation of natural sorting (posted in the comments here) since it is significantly faster than my original answer.


If you wish to sort text with floats, then you'll need to change the regex from one that matches ints (i.e. (\d+)) to a regex that matches floats:

import re

def atof(text):
try:
retval = float(text)
except ValueError:
retval = text
return retval

def natural_keys(text):
'''
alist.sort(key=natural_keys) sorts in human order
http://nedbatchelder.com/blog/200712/human_sorting.html
(See Toothy's implementation in the comments)
float regex comes from https://stackoverflow.com/a/12643073/190597
'''
return [ atof(c) for c in re.split(r'[+-]?([0-9]+(?:[.][0-9]*)?|[.][0-9]+)', text) ]

alist=[
"something1",
"something2",
"something1.0",
"something1.25",
"something1.105"]

alist.sort(key=natural_keys)
print(alist)

yields

['something1', 'something1.0', 'something1.105', 'something1.25', 'something2']

Sorting a list of strings based on numeric order of numeric part

You could use the re module to split each string into a tuple of characters and grouping the digits into one single element. Something like r'(\d+)|(.)'. The good news with this regex is that it will return separately the numeric and non numeric groups.

As a simple key, we could use:

def key(x):
# the tuple comparison will ensure that numbers come before letters
return [(j, int(i)) if i != '' else (j, i)
for i, j in re.findall(r'(\d+)|(.)', x)]

Demo:

lst = ['a1a', 'a2a', 'a5b', 'a10a', 'b1a', 'abc']
print(sorted(lst, key=key)

gives:

['a1a', 'a2a', 'a5b', 'a10a', 'abc', 'b1a']

If you want a more efficient processing, we could compile the regex only once in a closure

def build_key():
rx = re.compile(r'(\d+)|(.)')
def key(x):
return [(j, int(i)) if i != '' else (j, i)
for i, j in rx.findall(x)]
return key

and use it that way:

sorted(lst, key=build_key())

giving of course the same output.



Related Topics



Leave a reply



Submit