Search code examples
javaeclipse-plugincomparatorcollectors

Sort elements based on their String property in case insensitive way


The following code works but it does take into account upper or lower case, and the result is a non alphabetically ordered list:

List<Pair<IContributionItem, String>> itemsList = new ArrayList<>();

Comparator<Pair<IContributionItem, String>> filePathComparator = Comparator.comparing(Pair<IContributionItem, String>::getPathToFile);
        itemsList = itemsList.stream().sorted(filePathComparator).collect(Collectors.toList()); 

Then I came across String.CASE_INSENSITIVE_ORDER so I tried to add it to it:

Comparator<Pair<IContributionItem, String>> filePathComparator = Comparator.comparing(Pair<IContributionItem, String.CASE_INSENSITIVE_ORDER>::getPathToFile);
        itemsList = itemsList.stream().sorted(filePathComparator).collect(Collectors.toList()); 

But it gives an error: String.CASE_INSENSITIVE_ORDER cannot be resolved to a type.

What would be solution or workaround to accommodate the code?


Solution

  • Problem

    When we use Comparator.comparing(Function<? super T,? extends U> keyExtractor) elements are ordered based on value of key (object property) pointed out by keyExtractor. Sorting algorithm here uses the natural order defined by class of selected key.
    Such class (or its ancestor) needs to implement Comparable<T> interface which forces implementation of public int compareTo(T other) method where comparison mechanism for sorting algorithms is defined.

    Since your keyExtractor was extracting key of type String, the natural order defined in String class was applied, and that order is case-sensitive.

    Solution

    To build Comparator which will compare element based on its key (object property), but at the same time use different order than natural one for that key, we can use overloaded version of previous method, specifically Comparator.comparing(Function<? super T,? extends U> keyExtractor, Comparator<? super U> keyComparator). Here the additiona/second parameter keyComparator allows us to pass different Comparator for selected key.

    Since you claimed that

    Comparator.comparing(Pair<IContributionItem, String>::getPathToFile)
    

    worked but in case-sensitive way, all you need to do is add String.CASE_INSENSITIVE_ORDER as second argument - the keyComparator

    Comparator.comparing(Pair<IContributionItem, String>::getPathToFile, String.CASE_INSENSITIVE_ORDER)
                                                          // add this  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    

    Extra

    BTW you don't need to use angle brackets with method references since type inference should be able to figure out correct generic type parameter based on context, so

    Comparator.comparing(Pair::getPathToFile, String.CASE_INSENSITIVE_ORDER)
    

    should also work fine.