I have a problem with sorting strings which include integers. If I use the below code I get sorting like: 1some, 2some, 20some, 21some, 3some, some
However I want it
Here is a self-contained example on how to do this (not particularly optimized):
final Pattern p = Pattern.compile("^\\d+");
String[] examples = {
"1some", "2some", "20some", "21some", "3some", "some", "1abc", "abc"
};
Comparator<String> c = new Comparator<String>() {
@Override
public int compare(String object1, String object2) {
Matcher m = p.matcher(object1);
Integer number1 = null;
if (!m.find()) {
return object1.compareTo(object2);
}
else {
Integer number2 = null;
number1 = Integer.parseInt(m.group());
m = p.matcher(object2);
if (!m.find()) {
return object1.compareTo(object2);
}
else {
number2 = Integer.parseInt(m.group());
int comparison = number1.compareTo(number2);
if (comparison != 0) {
return comparison;
}
else {
return object1.compareTo(object2);
}
}
}
}
};
List<String> examplesList = new ArrayList<String>(Arrays.asList(examples));
Collections.sort(examplesList, c);
System.out.println(examplesList);
Output
[1abc, 1some, 2some, 3some, 20some, 21some, abc, some]
Explanation
Pattern
to infer whether a number is in the String
's starting position.String
, it compares it as is to the second.String
s as is, againInteger
s instead of the whole String
s, hence resulting in a numerical comparison rather than a lexicographical oneString
s (thanks MihaiC for spotting this one)If you have alphanumeric string array you can directly sort it by using
Arrays.sort(Array_name)
and then to print:
for(String a : Array_name)
System.out.print(a);
Your solution lies in The Alphanum Algorithm and you can implement like this
This is a working solution is Java. If you have any suggestions on the code, please let me know on my Gist.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class FB {
public static int comparator(String s1, String s2) {
String[] pt1 = s1.split("((?<=[a-z])(?=[0-9]))|((?<=[0-9])(?=[a-z]))");
String[] pt2 = s2.split("((?<=[a-z])(?=[0-9]))|((?<=[0-9])(?=[a-z]))");
//pt1 and pt2 arrays will have the string split in alphabets and numbers
int i=0;
if(Arrays.equals(pt1, pt2))
return 0;
else{
for(i=0;i<Math.min(pt1.length, pt2.length);i++)
if(!pt1[i].equals(pt2[i])) {
if(!isNumber(pt1[i],pt2[i])) {
if(pt1[i].compareTo(pt2[i])>0)
return 1;
else
return -1;
}
else {
int nu1 = Integer.parseInt(pt1[i]);
int nu2 = Integer.parseInt(pt2[i]);
if(nu1>nu2)
return 1;
else
return -1;
}
}
}
if(pt1.length>i)
return 1;
else
return -1;
}
private static Boolean isNumber(String n1, String n2) {
// TODO Auto-generated method stub
try {
int nu1 = Integer.parseInt(n1);
int nu2 = Integer.parseInt(n2);
return true;
}
catch(Exception x) {
return false;
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String[] examples = {"1some", "2some", "20some", "21some", "3some", "some", "1abc", "abc"};
List<String> values = new ArrayList<String>(Arrays.asList(examples));
System.out.println(values);
Comparator<String> com = (o1,o2) -> {return comparator(o1,o2);}; //lambda expression
Collections.sort(values,com);
System.out.println(values);
}
}
Output:
[1some, 2some, 20some, 21some, 3some, some, 1abc, abc]
[1abc, 1some, 2some, 3some, 20some, 21some, abc, some]
First make an alphanumerical comparator splitting the string in String or Integer parts.
public class AlphaNumericalComparator implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
List<Object> parts1 = partsOf(o1);
List<Object> parts2 = partsOf(o2);
while (!parts1.isEmpty() && !parts2.isEmpty()) {
Object part1 = parts1.remove(0);
Object part2 = parts2.remove(0);
int cmp = 0;
if (part1 instanceof Integer && part2 instanceof Integer) {
cmp = Integer.compare((Integer)part1, (Integer)part2);
} else if (part1 instanceof String && part2 instanceof String) {
cmp = ((String) part1).compareTo((String) part2);
} else {
cmp = part1 instanceof String ? 1 : -1; // XXXa > XXX1
}
if (cmp != 0) {
return cmp;
}
}
if (parts1.isEmpty() && parts2.isEmpty()) {
return 0;
}
return parts1.isEmpty() ? -1 : 1;
}
private List<Object> partsOf(String s) {
List<Object> parts = new LinkedList<>();
int pos0 = 0;
int pos = 0;
boolean wasDigit = false;
while (true) {
if (pos >= s.length()
|| Character.isDigit(s.charAt(pos)) != wasDigit) {
if (pos > pos0) {
String part = s.substring(pos0, pos);
parts.add(wasDigit? Integer.valueOf(part) : part);
pos0 = pos;
}
if (pos >= s.length()) {
break;
}
wasDigit = !wasDigit;
}
++pos;
}
return parts;
}
};
Then use this comparator in your own one, in Java 8 you may simply use Comparator's static methods.
How to Sort String,AlphaNumeric and Numeric value in Java using Comparator
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class AlphaNumericSorting {
public static void main(String[] args) {
final Pattern p = Pattern.compile("^\\d+");
String[] examples = { "CD", "DE", "0A", "0B", "0C", "12", "0K", "TA", "0D", "01", "02", "11", "AB", "MN" };
Comparator<String> c = new Comparator<String>() {
@Override
public int compare(String object1, String object2) {
Matcher m = p.matcher(object1);
Integer number1 = null;
if (!m.find()) {
Matcher m1 = p.matcher(object2);
if (m1.find()) {
return object2.compareTo(object1);
} else {
return object1.compareTo(object2);
}
} else {
Integer number2 = null;
number1 = Integer.parseInt(m.group());
m = p.matcher(object2);
if (!m.find()) {
// return object1.compareTo(object2);
Matcher m1 = p.matcher(object1);
if (m1.find()) {
return object2.compareTo(object1);
} else {
return object1.compareTo(object2);
}
} else {
number2 = Integer.parseInt(m.group());
int comparison = number1.compareTo(number2);
if (comparison != 0) {
return comparison;
} else {
return object1.compareTo(object2);
}
}
}
}
};
List<String> examplesList = new ArrayList<String>(Arrays.asList(examples));
Collections.sort(examplesList, c);
System.out.println(examplesList);
}
}
OUTPUT:-
[AB, CD, DE, MN, TA, 0A, 0B, 0C, 0D, 0K, 01, 02, 11, 12]