Why is the uppercase not sorted correctly?
I am trying to sort List<String>
items. Here's unsorted List
and how it's currently sorted:
Unsorted: [Pineapple, pineapple, apple, apricot, Banana, mango, Mango, melon, peach]
Sorted: [apple, apricot, Banana, mango, Mango, melon, peach, Pineapple, pineapple]
Why Mango
does not fit in front Mango
and why Pineapple
before Pineapple
?
Here is my code:
import java.util.*;
import java.lang.*;
import java.io.*;
class Test {
public static void main (String[] args) throws java.lang.Exception {
List<String> fruits = new ArrayList<String>(7);
fruits.add("Pineapple");
fruits.add("pineapple");
fruits.add("apple");
fruits.add("apricot");
fruits.add("Banana");
fruits.add("mango");
fruits.add("Mango");
fruits.add("melon");
fruits.add("peach");
System.out.println("Unsorted: " + fruits);
Collections.sort(fruits, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareToIgnoreCase(o2);
}
});
System.out.println("Sorted: " + fruits);
}
}
source to share
As a comparison method was used compareToIgnoreCase()
, so it was comparing "Pineapple" and "Pineapple" as 0 (same string), leaving them in the order they were found when sorting, since Collections.sort makes sure that equal elements won reordering ... In other words, "Pineapple" appeared before "pineapple", so now that they are equal to the ropes due to ignore, "Pineapple" will remain before "pineapple".
Since the unsorted list has Pineapple before Pineapple, the comparison puts them in the sorted list in the same order. The same rules apply for "mango" and "mango". The comparison method you're looking for is just one compareTo()
that counts both upper and lower case letters.
source to share
Why doesn't "Mango" fit in front of "mango" and why "Pineapple" before "pineapple"?
According to your comparator, "Mango" and "Mango" compare are equal. Since stable , elements comparing the same are equal are returned in the order they were found in the original collection (an unstable sort will return them in no particular order).Collections.sort()
If you expect Mango to always be returned before Mango, your comparator needs to reflect that. This means that "Mango" should be compared less than "mango" (but more than "apple", "apricot", "banana", etc.).
One way to achieve this is with the following comparator:
Collections.sort(fruits, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
int ret = o1.compareToIgnoreCase(o2);
if (ret == 0) {
ret = o1.compareTo(o2);
}
return ret;
}
});
This will return:
Sorted: [apple, apricot, Banana, Mango, mango, melon, peach, Pineapple, pineapple]
source to share
Because you are using compareToIgnoreCase
which, as the name says, ignores case when comparing two strings. So, mango and mango are the same and they are left in the same order as they were (the sort is stable, for example: the equality element remains in the order in which they were before the sort.).
On the side of the note, you are comparing the same as String.CASE_INSENSITIVE_ORDER . compareToIgnoreCase
simplifications call this comparator.
source to share
According to the javadocs it is Collections.sort
guaranteed to be stable - the relative order of elements that are compared as equal is not changed by the sort. If you want to enforce orders that place uppercase letters in front of their lowercase equivalents, you need to use a different comparator that implements that ordering, the simplest way to implement that is likely to be java.text.RuleBasedCollator
.
source to share