'Java sorting list of array vs sorting list of list

I have a list of points where each point is a tiny list of size 2. I want to sort the list of points in increasing order of x and if x values are equal, I break tie by sorting in decreasing order of y.

I wrote a custom comparator to sort the points like this:

Collections.sort(points, (a, b) -> {
    if (a.get(0) != b.get(0)) {
        return a.get(0) - b.get(0);
    } return b.get(1) - a.get(1); 
});

Here's the input before sorting:

(2, 1000)
(9, -1000)
(3, 15)
(9, -15)
(5, 12)
(12, -12)
(5, 10)
(10001, -10)
(19, 8)
(10001, -8)

Here's the result produced after sorting with the above comparator:

(2, 1000)
(3, 15)
(5, 12)
(5, 10)
(9, -15)
(9, -1000)
(12, -12)
(19, 8)
(10001, -10)
(10001, -8)

Observations:

  1. The input is sorted in ascending order on x.
  2. (5, 12) was correctly put before (5, 10).
  3. (9, -15) was correctly put before (9, -1000).
  4. However, (10001, -10) was put before (10001, -8). Even though -8 is larger than -10.

Feel like I am missing something trivial. I experimented with a few other ways of writing the comparator like using Integer.compare(a, b) or just a.compareTo(t), but got the same result.

Finally, I changed the representation of point from List<Integer> to int[] and wrote the same comparator again. See results below:

Collections.sort(points, (a, b) -> {
    if (a[0] != b[0])
        return a[0] - b[0];
    return b[1] - a[1];
});

Input before sorting:

(2, 1000)
(9, -1000)
(3, 15)
(9, -150
(5, 12)
(12, -12)
(5, 10)
(10001, -10)
(19, 8)
(10001, -8)

After sorting:

(2, 1000)
(3, 15)
(5, 12)
(5, 10)
(9, -15)
(9, -1000)
(12, -12)
(19, 8)
(10001, -8)
(10001, -10)

So list of arrays is getting sorted correctly as (10001, -8) was correctly put before (10001, -10).

I am not able to understand why changing the representation of point resolved the issue and hence this question. I can give more details on how I am creating the List of points if required.



Solution 1:[1]

@Alexander Ivanchenko explains very well why you are seeing the behavior you do. One solution to the problem is to use Integer.compareTo():

Collections.sort(points, (a, b) -> {
    int xCompare = a[0].compareTo(b[0];
    if (xCompare != 0) {
        return xCompare;
    }
    retirm a[1].compareTo(b[1];
});

Beyond this, I suggest creating a Point class:

class Point {
    public int x;
    public int y;
}

Here I use public fields to follow the struct pattern. If you want to add getters and setters and other behavior, feel free to do so. Using a class to represent the structure of your data makes the code more understandable and easier to maintain. In fact, you can easily implement Comparable on a Point or a Comparator<Point> class.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1