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