19
int[] arr2 = new int[] {54, 432, 53, 21, 43};

I am using this to sort but it is giving an error.

Arrays.sort(arr2, (a, b) -> a - b);

This is also giving an error.

arr2.sort((a, b) -> a - b);
7
  • 18
    Never use a comparator like (a,b)->a-b for int values. It may work in some use cases, but the difference between two int values may be bigger than the int value range and cause overflows. Therefore, use (a,b) -> Integer.compare(a, b) resp. Integer::compare. To reverse the order, use (a,b) -> Integer.compare(b, a). Do not negate the value returned by a compare function, that will fail if the value is Integer.MIN_VALUE. Commented Jan 10, 2019 at 11:15
  • 4
    "giving error" what error? Please specify this information. Commented Jan 10, 2019 at 11:25
  • 3
    @IanKemp in this case, it’s obvious enough. Arrays don’t have a sort method and the sort​(T[] a, Comparator<? super T> c) method does not support primitive type arrays. Commented Jan 10, 2019 at 11:30
  • 3
    @Holger Whether it's obvious enough is irrelevant - the rules specify that a question must include a specific problem or error. "Giving error" is the same as saying "doesn't work", which is not helpful to anyone - especially not people who might be looking for the specific error caused by using a comparator like (a,b)->a-b with Integer.MIN_VALUE. Commented Jan 10, 2019 at 11:59
  • 4
    @cwa in Java, a two dimensional array is an array of arrays. Since an array is an object, a two dimensional array is therefore also an array of objects. In other words, when you have int[][] array, then, array instanceof Object[] will also be true. So, int[][] being an array of objects, you can use the generic method sort​(T[] a, Comparator<? super T> c). But read this comment again, using minus as comparator works for some (small) values but is broken in general and will lead to hard-to-track bugs Commented Jul 31, 2020 at 7:54

7 Answers 7

22

You could sort the input of type Integer[] as :

Integer[] arr2 = new Integer[] {54,432,53,21,43};
Arrays.sort(arr2, Comparator.reverseOrder());

or possibly with primitive types as :

int[] arr2 = new int[]{54, 432, 53, 21, 43};
int[] sortedArray = Arrays.stream(arr2)
        .boxed()
        .sorted(Comparator.reverseOrder()) // just use 'sorted()' for ascending order
        .mapToInt(Integer::intValue)
        .toArray();

or further using a trick from one of the existing answers (do note that it should be cautiously used with boundary values though) :

int[] sortedArray = Arrays.stream(arr2)
        .map(i -> -i).sorted().map(i -> -i) // just use 'sorted()' for ascending order
// Edit - use map(i -> ~i).sorted().map(i -> ~i) to be safe from the issue with Integer.MIN_VALUE
        .toArray();

Edit: For an in-place ascending order sort, you just need to perform :

int[] arr2 = new int[]{54, 432, 53, 21, 43};
Arrays.sort(arr2);
Sign up to request clarification or add additional context in comments.

4 Comments

For ascending order, you can use Arrays.stream(arr2).sorted().toArray() or just sort in-place with Arrays.sort(arr2). However, be aware that the trick with negating the values does not work if one or more occurrences of Integer.MIN_VALUE are among the values.
@Holger true, that's what I meant in the note before the map.sort.map solution about boundary values.
As explained in Stuart Marks’ answer, using binary not (~) instead of minus (-) would solve the issue with Integer.MIN_VALUE.
@Holger Thanks for sharing. Would spend some time reading Stuart's answer later for sure.
13

Given

int[] array = ... ;

To sort ascending, simply do

Arrays.sort(array);

Here's a pretty way to sort descending:

Arrays.setAll(array, i -> ~array[i]);
Arrays.sort(array);
Arrays.setAll(array, i -> ~array[i]);

This is a tiny bit slower than sorting ascending and then reversing the array; it has to do an extra pass over the array. The runtime is dominated by the sorting for an array of any significant size, so it's unlikely to be noticeable.

This works by doing a bitwise complement of the int values before and after the sort. This provides an exact, lossless reversal of the ordering of every possible int value. To see this, you have to understand that Java ints use two's complement representation. Consider if ints were to have only three bits. All the values would be as follows:

         100  101  110  111  000  001  010  011
          -4   -3   -2   -1   0    1    2    3
MIN_VALUE ^

The bitwise complement operator ~ inverts every bit. You can see by inspection that this reflects the table about a pivot point between -1 and 0, so -4 becomes 3, -3 becomes 2, etc. Also, another complement will restore the original value. Thus, an ascending sort on the complemented values is a descending sort on the original values.

Note that this differs from negation - which doesn't do the right thing here. It reflects the table at zero, so the negation of zero is zero, the negation of -1 is 1, etc. This is asymmetric, because the negation of MIN_VALUE is MIN_VALUE. Thus, using negation in an attempt to perform a descending sort doesn't work.

Finally, boxing and using a Comparator works, but it's considerably slower, and it allocates a separate object for (almost) every int value. I recommend avoiding boxing.

2 Comments

Hi! Wouldn't the fact that you need to do all this work with the bits mean that a new method is needed? i.e. Arrays.sortDescending
@FedericoPeraltaSchaffner Quite possibly. It might be useful to add some primitive array operations. This does seem to be a frequently asked question, and common answers (such as those that involve boxing) perform quite poorly.
7

Sort in ascending order :

  1. int[] ascArr = Arrays.stream(arr2).boxed().sorted(Comparator.naturalOrder())
                                      .mapToInt(Integer::intValue).toArray();
    
  2. int[] ascArr = IntStream.of(arr2).boxed().sorted((a, b) -> Integer.compare(a, b))
                                     .mapToInt(Integer::intValue).toArray();
    
  3. int[] ascArr = Arrays.stream(arr2).sorted().toArray();


Sort in descending order :

  1. int[] descArr = Arrays.stream(arr2).boxed().sorted(Comparator.reverseOrder())
                                       .mapToInt(Integer::intValue).toArray();
    
  2. int[] descArr = IntStream.of(arr2).boxed().sorted((a, b) -> Integer.compare(b, a))
                                      .mapToInt(Integer::intValue).toArray();
    

Comments

4

There are different ways to create a sorted array of ints out of an unsorted one using streams, as the other answers show. These approaches have the disadvantage of either requiring boxing/unboxing (so that a Comparator<Integer> can be used), or that new arrays are needed to accommodate the elements.

Here's a way to sort in-place without boxing/unboxing. First, in ascending order:

int[] arr2 = ...
Arrays.sort(arr2);

Unfortunately, there's no way to sort in-place in descending order using a single-line operation. You will need to sort ascending first, then reverse the array:

int[] arr2 = ...
Arrays.sort(arr2);

int size = arr2.length;
for (int left = 0; left < size / 2; left++) {
    int right = size - i - 1;
    int temp = arr2[right];
    arr2[right] = arr2[left];
    arr2[left] = temp;
}

EDIT: As @Holger points out in the comments, the for loop above could be improved as follows:

for (int left = 0, right = arr2.length - 1; left < right; left++, right--) {
    int temp = arr2[right];
    arr2[right] = arr2[left];
    arr2[left] = temp;
}

An alternative is to sort in ascending order and then place the elements in reverse order into a new array:

int[] arr2 = ...
Arrays.sort(arr2);

int size = arr2.length;
int[] reversed = new int[size];
Arrays.setAll(reversed, i -> arr2[size - i - 1]);

This uses Arrays.setAll to accomplish the task.

1 Comment

You may consider a simpler for(int left = 0, right = arr2.length-1; left < right; left++, right--) … which may also be more efficient in some cases.
2

If you explicitly need a custom comparator lambda, try this one:

    int[] arr2 = new int[] {54,432,53,21,43};
    int[] arr3 = IntStream.of(arr2).boxed().sorted((a, b) -> a - b).mapToInt(Integer::intValue).toArray();

Comments

2
public class lambdaTest {

    public static void main(String[] args) {
        int[] arr2 = new int[] {54,432,53,21,43};

        int[] sorted = IntStream.of(arr2)
                .boxed()
                .sorted(Comparator.reverseOrder())
                .mapToInt(i -> i)
                .toArray();
        System.out.println("In decending Order:");
        for(int ss : sorted)
        {
            System.out.print(ss+", ");
        }
        System.out.println();
        int[] reversed = IntStream.range(0, sorted.length)
                .map(i -> sorted[sorted.length-i-1])
                .toArray();
        System.out.println("In Ascending Order: ");

        for(int ss1 : reversed)
        {
            System.out.print(ss1+", ");
        }
    }

}

OUTPUT

In decending Order:

432, 54, 53, 43, 21,

In Ascending Order:

21, 43, 53, 54, 432,

Edit: much simpler to sort in natural order (IntStream.of(arr2) .sorted() .toArray())

Thanks to Holger

3 Comments

It would be much simpler to sort in natural order (IntStream.of(arr2) .sorted() .toArray()) and reverse that, to get both, instead of sorting in reverse order and reverse that again.
Yeah, i got it, but i presented other way of doing it :?, hope it is ok??
Sure, but there’s an advantage in the approach of reversing the array, as together with a straight-forward ascending order sort, you can do it without any boxing overhead. That advantage gets lost when doing the first sort with boxed values (as unavoidable when using a Comparator).
-2
int[] arr2 = new int[] {54, 432, 53, 21, 43};
int[] answer = Arrays.stream(arr2).boxed()
    .sorted(Comparator.comparing(Integer::intValue).reversed())
    .mapToInt(Integer::intValue)
    .toArray()

2 Comments

Although this code might answer the question, I recommend that you also provide an explanation what your code does and how it solves the problem of the question. Answers with an explanation are usually more helpful and of better quality, and are more likely to attract upvotes.
Arrays.sort(arr2, (a, b) -> a - b); This gives an error because Arrays.sort() expects a comparator only for objects (like Integer[]). Since arr2 is a primitive int[], you should use Arrays.sort(arr2); instead. arr2.sort((a, b) -> a - b); This gives an error because arr2 is a primitive array (int[]), and primitive arrays do not have a .sort() method.

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.