0

Suppose I have a 2D integer array of

int[][] arr = new int [][] {
            {1,1},
            {2,222},
            {3,32},
            {4,13},
            {5,1144},
            {6,111},
            {7,12341},
            {8,111}
        };

I want to sort this array in an increasing order of second element of each row.

[[1, 1], [4, 13], [3, 32], [8, 111], [6, 111], [2, 222], [5, 1144], [7, 12341]]

But notice, when the second element's values are same as in

[8, 111] and [6, 111]

The sorting order reversed.

So here is what I attempted

Arrays.sort(arr, (a,b) -> a[1]==b[1]? b[1]-a[1]: a[1]-b[1]);

Whenever second elements are equal, reverse the sorting order to descending order, otherwise keep the ascending order.

After running this code, I get a result of

[[1, 1], [4, 13], [3, 32], [6, 111], [8, 111], [2, 222], [5, 1144], [7, 12341]]

Notice how the

 [6, 111], [8, 111]

are still in the wrong order.

4
  • Note how a[1]==b[1]? b[1]-a[1] :a[1]-b[1] will always be 0 or a[1]-b[1] (a[1]==b[1]? b[1]-a[1] is always 0) Commented Apr 16, 2021 at 13:08
  • 2
    I don't fully understand but you probably need Arrays.sort(arr, (a,b) -> a[1]==b[1]? b[0]-a[0]: a[1]-b[1]); If second elements are equal, compare first elements i.e. elements at 0th index. Commented Apr 16, 2021 at 13:10
  • 1
    Your reported output after the change shows a different order but you claim it is the same. Commented Apr 16, 2021 at 13:13
  • 1
    Are you saying you want a stable sort? That's already what the Java sorting algorithm does, if you just sort on the second element. Commented Apr 16, 2021 at 13:26

4 Answers 4

2

Maybe this?

Arrays.sort(arr, (a,b) -> a[1]==b[1]? b[0]-a[0]: a[1]-b[1])
Sign up to request clarification or add additional context in comments.

2 Comments

Comparing using subtraction can result in overflow. You'd think that Integer.MAX_VALUE is bigger than Integer.MIN_VALUE, but Integer.MAX_VALUE - Integer.MIN_VALUE is negative.
It is very bad technique to subtract values to satisfy the Comparator contract. Try it with values near Integer.MIN_VALUE and Integer.MAX_VALUE and see what you get. Always return 1, -1, or 0. or use Integer.compare() or Integer.compareTo()
2

I would try it like this using a Comparator. If you want the first numbers in ascending order, then remove the reverseOrder comparator. Otherwise, leave it in. If you want to leave the first numbers in their relatively same positions when the second numbers are equal, then just sort on the second number. This will work since the sorting algorithm is stable.

Arrays.sort(arr, Comparator.comparingInt((int[] a) -> a[1])
        .thenComparing(a -> a[0], Comparator.reverseOrder()));

for (int[] a : arr) {
    System.out.println(Arrays.toString(a));
}

Prints

[1, 1]
[4, 13]
[3, 32]
[8, 111]
[6, 111]
[2, 222]
[5, 1144]
[7, 12341]

1 Comment

It's a pity there's no thenComparingInt(function, comparator) which forces you to write thenComparing instead, or using the technique in my answer to avoid boxing.
1

Using Integer.compare method:

Arrays.sort(arr, (a,b) -> a[1]==b[1]?
                          Integer.compare(b[0], a[0]):
                          Integer.compare(a[1], b[1]));

Comments

1

Use this:

    Arrays.sort(arr, Comparator.comparingInt((int[] a) -> a[1])
            .thenComparing(Comparator.comparingInt((int[] a) -> a[0]).reversed()));

1 Comment

Just in case you didn't know, reversed() actually reverses every comparator that precedes it. But since you put in a Comparator within the thenComparing method, it worked. It's a subtlety that I have found that most are not aware of.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.