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
How to Add Local .Jar File Dependency to Build.Gradle File
Compare Two Objects With .Equals() and == Operator
How to Convert Jsonstring to Jsonobject in Java
Initialization of an Arraylist in One Line
"Missing Return Statement" Within If/For/While
How to Unescape a Java String Literal in Java
Java Hashmap: How to Get Key from Value
What Is the Equivalent of the C++ Pair≪L,R≫ in Java
How to Loop Through a Hashmap in Jsp
What Does the ^ Operator Do in Java
Simpledateformat Ignoring Month When Parsing
How to Generate Exceptions from Repaintmanager
How to Concatenate Two Strings in Java
Do Subclasses Inherit Private Fields
Convert Java.Util.Date to String