Home > Mobile >  List.sort with two fields
List.sort with two fields

Time:08-21

I saw this code on leetcode discussion section, but I was not able to understand it. please help here.

HashMap<Character,Integer> map = new HashMap<>();
    for(char ch: s.toCharArray()){
        map.put(ch,map.getOrDefault(ch,0) 1);
    }
    List<Character> list = new ArrayList<>(map.keySet());//convert hashmap keys into list
    list.sort((x,y) -> map.get(y) - map.get(x));

Im not able to understand the meaning of the below line.

list.sort((x,y) -> map.get(y) - map.get(x));

CodePudding user response:

There is actually a surprising number of things going on with that one short line: list.sort((x,y) -> map.get(y) - map.get(x));.

List.sort( Comparator comparator )

The List.sort method takes a Comparator object as an argument.

@FunctionalInterface

If you look at the Comparator interface, you’ll see that it is annotated by @FunctionalInterface. To quote the Javadoc, “Conceptually, a functional interface has exactly one abstract method.”.

Lambda

This code:

(x,y) -> map.get(y) - map.get(x)

… is lambda syntax that acts as an implementation of that single abstract method.

The compiler can infer this implemented method is the compare method of Comparator, the only abstract method found on Comparator.

Comparator#compare

The Comparator#compare method returns an int integer number. To quote the Javadoc: that returned number means “a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.”.

The value side of the key-value pairings in your HashMap is of the type Integer class. So merely subtracting one value Integer object from another is a seemingly clever way to determine the integer number to be returned by the compare number.

Integer overflow

However, as commented below, this approach is mathematically flawed. ⚠️

The subtraction could result in an integer overflow. Better to delegate the comparing work to a method found in the Integer class: Integer.compare.

( x , y ) -> Integer.compare( x , y ) 

If curious about the implementation of that method, examine the open source code on the OpenJDK project. Excerpt:

public static int compare(int x, int y) {
    return (x < y) ? -1 : ((x == y) ? 0 : 1);
}

An alternative is the use of a Comparator object returned by the static Comparator.comparingInt method.

[Caveat: I’ve not yet tested this code.]

list.sort( Comparator.comparingInt( list :: get ) )

That list :: get part is a method reference.

Auto-boxing

Also, the map.get(y) - map.get(x) part invokes auto-boxing.

Each get call returns an object of type Integer class. Using the subtraction sign - with Integer objects makes no sense directly; objects cannot be subtracted. However the compiler is smart enough to recognize that a Integer object can be converted to a int primitive. And two int primitives can be subtracted.

CodePudding user response:

You can use Go to Declaration in your IDE. ( Ctrl B in Intellij for example) and see the method:

sort(Comparator<? super E> c)

So there are not 2 fields, is only one, a comparator as described in previous answer.

Maybe it would help you to read clear if you extract it as variable ( Ctrl Alt V in Intellij).

Comparator<Character> characterComparator = (x, y) -> map.get(y) - map.get(x);

Also in this case it can be simplified to :

Comparator.comparingInt(map::get)

So the sort would be:

list.sort(Comparator.comparingInt(map::get));
  • Related