简体   繁体   中英

List.sort with two fields

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));

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.

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));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM