简体   繁体   中英

Java How to sort an array of signed integers in descending order ignoring the signs?

The title is self-explanatory. Eg

[2, 1, 0, -2, -5]

will become

[-5, -2, 2, 1, 0]

My strategy is to first sort them in ascending order, then sort them separately in terms of negative and positive numbers but my strategy is vague. I know this is vague but your answers would help me a lot.

Short version :

Integer[] ary = { 2, 1, 0, -2, -5 };

Arrays.sort(ary, (Integer i1, Integer i2) -> Math.abs(i2) - Math.abs(i1));
System.out.println(Arrays.toString(ary));

No need for ArrayList. Integers instead of int are needed though.

My first answer was:

I first convert from int[] to List< Integer >, and use a Lambda comparator to sort it the way you want.

int[] ary = { 2, 1, 0, -2, -5 };

List<Integer> intList = new ArrayList<Integer>();
for (int index = 0; index < ary.length; index++) { 
  intList.add(ary[index]);
} 

intList.sort((Integer i1, Integer i2) -> Math.abs(i2) - Math.abs(i1));

System.out.println(intList);

it returns

[-5, 2, -2, 1, 0]

This is a bit messy if you really need an int[] .

You can define a Comparator, but since Generics don't work with primitives, it won't work with int[] .

Comparator<Integer> integerComparator = (x, y) -> Integer.compare(Math.abs(x), Math.abs(y));

With List<Integer> and Integer[] it is easier:

List<Integer> integerList = Arrays.asList(2, 1, 0, -2, -5);
Integer[] integerArray = new Integer[] {2, 1, 0, -2, -5};


integerList.sort(integerComparator.reversed());
Arrays.sort(integerArray,integerComparator.reversed());
System.out.println("ints = " + integerList);
System.out.println("integerArray = " + Arrays.toString(integerArray));

With an int[] , it is messier. You can use an IntStream and box it using boxed() to a Stream<Integer> . But then, you will get a performance hit, but unless you are dealing with huge arrays or use that in a critical part of an application, it won't be a problem.

int[]primitiveArray = new int[]{2, 1, 0, -2, -5};

int[] ints = IntStream.of(primitiveArray)
        .boxed()
        .sorted(integerComparator.reversed())
        .mapToInt(Integer::valueOf)
        .toArray();

System.out.println("ints = " + Arrays.toString(ints));

Simply sort the input comparing(Math::abs, reverseOrder()) :

@Test
public void test() {
    List<Integer> input = asList(2, 1, 0, -2, -5);

    List<Integer> output = input.stream()
            .sorted(comparing(Math::abs, reverseOrder()))
            .collect(toList());

    System.out.println(output);
}

Outputs

[-5, 2, -2, 1, 0]

Requires imports:

import org.junit.Test;

import java.util.List;

import static java.util.Arrays.asList;
import static java.util.Comparator.comparing;
import static java.util.Comparator.reverseOrder;
import static java.util.stream.Collectors.toList;

This is a bit of an over-object-oriented solution that doesn't require the memory for copying the array to a List, doesn't require unpacking the List back to an array, and you don't need to reinvent any sorting algorithms:

final int[] array = new int[] {2, 1, 0, -2, -5};
Collections.sort(
        new AbstractList<Integer>() {
            public Integer get(int index) {
                return array[index];
            }

            public int size() {
                return array.length;
            }

            @Override
            public Integer set(int index, Integer element) {
                int old = array[index];
                array[index] = element;
                return old;
            }
        },
        new Comparator<Integer>() {
            public int compare(Integer o1, Integer o2) {
                return Math.abs(o1) - Math.abs(o2);
            }
        }
);

If you have Commons Lang, it's a lot cleaner:

final int[] array = new int[] {2, 1, 0, -2, -5};
Collections.sort(
        ArrayUtils.toObject(array),
        new Comparator<Integer>() {
            public int compare(Integer o1, Integer o2) {
                return Math.abs(o1) - Math.abs(o2);
            }
        }
);

The comparator from another answer, ((Integer i1, Integer i2) -> Math.abs(i2) - Math.abs(i1)) , is just the lambda version if the one here. If you have Java 8+, feel free to use either.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM