I'm trying to perform a descending sort on a column that contains an underscore within the string. This is my descending sort method.
protected void validateDescendingOrder(Integer column) {
// create a column list
List<String> columnList = getColumnList(column);
// create a new list and sort
List<String> sortedcolumnList = new ArrayList<String>();
sortedcolumnList.addAll(columnList);
Collections.sort(sortedcolumnList, new Comparator<String>() {
public int compare(String o1, String o2) {
if (o1.contains("_") && o2.contains("_")) {
return compare(o1.substring(1), o2.substring(1));
}
if (o1.contains("_")) {
return 1;
}
if (o2.contains("_")) {
return -1;
}
return o1.compareTo(o2);
}
});
// sort the list using the custom comparator
Collections.sort(sortedcolumnList, Collections.reverseOrder(String.CASE_INSENSITIVE_ORDER));
//sortedcolumnList.sort(customComparator);
System.out.println(sortedcolumnList);
System.out.println(columnList);
// compare the original list order with the sorted list to make sure they match
assertEquals(sortedcolumnList, columnList);
I'm expecting my sort to return Test_jenn, Test_Community, TestRelease, TestCom1, test1, but instead it's returning TestRelease, TestCom1, Test_jenn, Test_Community, test1
Collections.sort()
is being called twice, and since calling Collections.sort()
does re-sort the list, the previous sort is (almost)¹ ignored.
The posted code is basically:
Collections.sort(list, comparator1);
Collections.sort(list, comparator2);
so the resulting order is the one given by comparator2 - reverseOrder(CASE_INSENSITIVE_ORDER)
.
The sorting of compartor1 - the anonymous class using underscores - is ignored!
That is, doing something like:
Collections.sort(list, Collections.reverseOrder(comparator3));
does not reverse the previous order of the list; it does sort using the given comparator3
in reverse order. In posted code the Comparator being reversed is String.CASE_INSENSITIVE_ORDER
, so the list ends up sorted in descending case-insensitive order of the strings.
Remove the second sort
Collections.sort(sortedcolumnList, Collections.reverseOrder(String.CASE_INSENSITIVE_ORDER));`
Alternatives to reverse the anonymous Comparator:
Collections#reverseOrder
Collections.reverseOrder( new Comparator<String>() {
public int compare(String o1, String o2) {
if (o1.contains("_") && o2.contains("_")) {
return compare(o21.substring(1), o2.substring(1));
}
if (o2.contains("_")) {
return 1;
}
if (o1.contains("_")) {
return -1;
}
return o2.compareTo(o1);
}
} )
compare
new Comparator<String>() {
public int compare(String o1, String o2) {
if (o1.contains("_") && o2.contains("_")) {
return compare(o21.substring(1), o2.substring(1));
}
if (o2.contains("_")) {
return 1;
}
if (o1.contains("_")) {
return -1;
}
return o2.compareTo(o1);
}
}
new Comparator<String>() {
public int compare(String o1, String o2) {
if (o1.contains("_") && o2.contains("_")) {
return compare(o1.substring(1), o2.substring(1));
}
if (o1.contains("_")) {
return -1;
}
if (o2.contains("_")) {
return 1;
}
return - o1.compareTo(o2);
}
}
Case Insensitive
To obtain a case insensitive ordering, use compareToIgnoreCase()
instead of compareTo()
.
Recursive Call
I am not sure what is the intention of the recursive call of compare
. For me it seems to be an expensive and error-prone way for ignoring everything before the underscores of both strings. The compare
method can eventually be called to compare each element with each other element, that is, it can be called very often, a non-recursive solution would be more indicated. Suggestion: instead of contains
use indexOf()
to search the underscores and substring()
to ignore everything up to that index.
as I wrote, not sure what the exact requirement are.
1 - Collections#sort
"is guaranteed to be stable: equal elements will not be reordered as a result of the sort." (javadoc)