How to sort integer array in ascending and descending order using lambda only in java

Viewed 23539
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);
6 Answers

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

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.

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

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.

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

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