0

I found the following code, which sorts the personList array by the Person's age in descending order.

personList.sort((Person p1, Person p2) -> p2.getAge() - p1.getAge());

However, I'm having trouble understanding how it works. It seems that the sort() function subtracts p1 and p2's age but I don't get how that allows the function to return the sorted array.

How does sort() iterate over the array and uses the comparator for every object in that array?

janhoegs03
  • 61
  • 3
  • 1
    `sort` do not subtract anything, `sort` sorts. What about reading first https://docs.oracle.com/javase/8/docs/api/java/util/List.html#sort-java.util.Comparator- ? – PeterMmm Oct 11 '22 at 16:57

3 Answers3

4

This is just a (perhaps) overly clever implementation of a comparator in Java.

The Comparator interface says that compare(p1, p2) should return a negative number if p1 should go before p2, zero if they should be treated as the same, and a positive number if p1 should go after p2.

Subtraction happens to do that! If p1.getAge() is less than p2.getAge(), then p2.getAge() - p1.getAge() is a positive number, so p1 will go after p2 -- which is just another way of saying "descending order of age."

Writing the code this particular way is, however, not a great idea on several levels -- most notably that subtraction, while a cute trick, doesn't work for all ints. (You're technically fine for ages, which will always be nonnegative, but you shouldn't have to know that.) Additionally, figuring out the correct ordering takes a few seconds for a reader of the code -- even one who knows all this. (For you, it took a StackOverflow question.)

A better version is

import static java.util.Comparator.*;

personList.sort(comparingInt(Person::getAge).reversed());
Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
2

Nothing's being subtracted. The Javadoc for List#sort is clear; you're basically comparing two elements together to determine what rank they should be in. This is specified by the Comparator itself in that you have some numerical value that is less than zero, zero or greater than zero to determine order.

In your case, if p1's age was 30 and p2's age was 20, then you'd sort with p1 coming in before p2 in descending order.

The mechanism of how it does it is...internal? Depends on the kind of sort that someone wanted to implement for this, and I think it could change depending on what size the collection is, since different sorts work better in different cases (e.g. no one cares about bubble sort on a list of size two, but you'd get into exotics with TimSort if you had a sufficiently large list).

Makoto
  • 104,088
  • 27
  • 192
  • 230
1

A comparator works as follows.

compare(a,b) returns a negative value if a < b, a positive value if a > b, and a 0 if a == b. So by subtracting ages, you get the -,+ and 0 effect. In your case, you are sorting them in reverse order because the first parameter is subtracted from the second.

However, that is a real bad way of doing it and can lead to problems for some number sets. Here is a better way for a descending sort.

Comparator<Integer> comp = (a,b)-> a < b ? 1 : a > b ? -1 : 0;

The above uses the ternary operator which says for (a op b) ? r : s, if a op b is true, return r else return s where r and s may be constants or expressions.

In some cases you can use the predefined comparators in the Comparator interface javadoc. In your case, that would be the reversed() comparator which reverses the natural order (ascending for integers) comparison.

WJS
  • 36,363
  • 4
  • 24
  • 39