Sorting a Collection Containing Strings And/Or Numbers

how to sort a collection which has strings, integers and alphanumerics in java

//the fishing technique

List<String> values = new ArrayList<String>();
values.add("AB");
values.add("A012B");
values.add("CD");
values.add("1");
values.add("10");
values.add("01");
values.add("9");
values.add("I");
Collections.sort(values, new Comparator<String>() {

@Override
public int compare(String o1, String o2) {
// TODO tweak the comparator here
try{
Integer integer1 = Integer.valueOf(o1);
Integer integer2 = Integer.valueOf(o2);
return integer1.compareTo(integer2);
}catch (java.lang.NumberFormatException e) {
return o1.compareTo(o2);
}
}
});
System.out.println(values);
}

//not enough???

//here is the fish

public static void main(String[] args) throws Exception {
List<String> values = new ArrayList<String>();
values.add("AB");
values.add("A012B");
values.add("CD");
values.add("1");
values.add("10");
values.add("01");
values.add("9");

int maxLen = 0;
for (String string : values) {
if (string.length() > maxLen) {
maxLen = string.length();
}
}

Collections.sort(values, new MyComparator(maxLen));

System.out.println(values);
}

public static class MyComparator implements Comparator<String> {
private int maxLen;
private static final String REGEX = "[0-9]+";

public MyComparator(int maxLen) {
this.maxLen = maxLen;

}

@Override
public int compare(String obj1, String obj2) {
String o1 = obj1;
String o2 = obj2;
// both numbers
if (o1.matches("[1-9]+") && o2.matches("[1-9]+")) {
Integer integer1 = Integer.valueOf(o1);
Integer integer2 = Integer.valueOf(o2);
return integer1.compareTo(integer2);
}

// both string
if (o1.matches("[a-zA-Z]+") && o2.matches("[a-zA-Z]+")) {
return o1.compareTo(o2);
}

Pattern p = Pattern.compile(REGEX);
Matcher m1 = p.matcher(o1);
Matcher m2 = p.matcher(o2);

List<String> list = new ArrayList<String>();
while (m1.find()) {
list.add(m1.group());
}
for (String string : list) {
o1.replaceFirst(string, leftPad(string, "0", maxLen));
}

list.clear();

while (m2.find()) {
list.add(m2.group());
}
for (String string : list) {
o2.replaceFirst(string, leftPad(string, "0", maxLen));
}
return o1.compareTo(o2);

}
}

public static String leftPad(String stringToPad, String padder, Integer size) {

final StringBuilder strb = new StringBuilder(size.intValue());
final StringCharacterIterator sci = new StringCharacterIterator(padder);

while (strb.length() < (size.intValue() - stringToPad.length())) {
for (char ch = sci.first(); ch != CharacterIterator.DONE; ch = sci.next()) {
if (strb.length() < (size.intValue() - stringToPad.length())) {
strb.insert(strb.length(), String.valueOf(ch));
}
}
}

return strb.append(stringToPad).toString();
}

How to sort a String collection that contains numbers?

You could either create a custom Comparator to split the String and parse it into two ints, or create a bespoke class to represent each String and store that in the Collection instead. I favour the latter approach as you only incur the overhead of splitting / parsing the String once; e.g.

public class Data implements Comparable<Data> {
private final int prefix;
private final int suffix;

public Data(String str) {
String[] arr = str.split(":");

if (arr.length != 2) {
throw new IllegalArgumentException();
}

this.prefix = Integer.parseInt(arr[0]);
this.suffix = Integer.parseInt(arr[1]);
}

public int compareTo(Data data) {
// Should really avoid subtraction in case of overflow but done to keep code brief.
int ret = this.prefix - data.prefix;

if (ret == 0) {
ret = this.suffix - data.suffix;
}

return ret;
}

// TODO: Implement equals and hashCode (equals to be consistent with compareTo).

public String toString() { return String.format("%d:%d", prefix, suffix); }
}

Then it's simply a case of storing some Data objects in your Collection; e.g.

List<Data> l = new ArrayList<Data>();
l.add(new Data("13:56"));
l.add(new Data("100:16"));
l.add(new Data("9:1"));
Collections.sort(l);

One more thing - You mention you're using a Vector. You should try to avoid using Vector / Hashtable as these have been superseded by List / Map, which were introduced as part of the Collections Framework in JDK 1.2.

How do I sort a list of string and numbers in numerical order?

Since your listId is String ,the list gets sorted lexographically. Instead you could first convert the String to an Integer and then sort it. Below is the illustration.

Collections.sort(tempList, (mainData, t1) -> Integer.parseInt(mainData.getListId())-Integer.parseInt(t1.getListId());

Sorting an Arraylist that contains strings with numbers

Define your own class that implements Comparator<String>. In the compare method, extract the numbers out of the first part of the string arguments and compare them, returning -1, 0, or 1, if the first number is less than, equal to, or greater than, the second number.

Then you can pass an instance of your comparator (along with your ArrayList) to Collections.sort.

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]

How to correctly order an ArrayList<String> containing Strings and numbers?

That's because the default String Comparator uses lexicographical order -- i.e. character by character, as in a dictionary. Since "1" comes before "2", any String starting with "1" will precede any other starting with "2".

You should use a custom comparator to implement Natural Sorting. A good example would be Alphanum, from Dave Koelle, which you would use like this:

Collections.sort(myarraylist, new AlphanumComparator());

Sorting Array List containing strings and integers

You can simply use swapping method just like in regular arrays. The only difference is that we use set(index, "value") method to update a specific string at specified index.

public static void sort (ArrayList<String> arr){    

int N = arr.size();
int E = N-1;
String temp;
boolean flag = true;

while(flag){
flag=false;

for(int a = 0 ; a < E ; a++){
if(Integer.parseInt(arr.get(a).substring(arr.get(a).indexOf(" ")+1)) >
Integer.parseInt(arr.get(a+1).substring(arr.get(a+1).indexOf(" ")+1))) {

temp=arr.get(a);
arr.set(a, arr.get(a+1));
arr.set(a+1, temp);

flag=true;
}
}
E--;
}}

The sorting algorithm is bubble sort. I have used it due to simplicity. You can use any other sorting algorithm if you want.

Then, you can call the sort() function in main method:

    public static void main(String[] args) {

ArrayList<String> arr = new ArrayList<String>();

arr.add("a 98");
arr.add("a 23");
arr.add("c 11");

sort(arr);
}

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]


Related Topics



Leave a reply



Submit