Java Как отсортировать массив целых чисел со знаком в порядке убывания, игнорируя знаки?

#java

#java

Вопрос:

Название говорит само за себя. Например

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

станет

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

Моя стратегия состоит в том, чтобы сначала отсортировать их в порядке возрастания, затем отсортировать их отдельно по отрицательным и положительным числам, но моя стратегия расплывчата. Я знаю, что это расплывчато, но ваши ответы мне бы очень помогли.

Комментарии:

1. Вы пробовали какое-либо решение, вы должны добавить его?

2. Напишите пользовательский компаратор, который использует Math.abs() внутри.

3. На самом деле это немного сложно сделать чисто, потому что Comparator не будет работать с примитивами. Это обязательно должно быть int[] или это может быть целое число[]?

Ответ №1:

Краткая версия :

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

Нет необходимости в ArrayList. Однако необходимы целые числа вместо int.

Мой первый ответ был:

Сначала я конвертирую из int[] в List< Integer> и использую лямбда-компаратор, чтобы отсортировать его так, как вы хотите.

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

он возвращает

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

Ответ №2:

Это немного запутанно, если вам действительно нужно int[] .

Вы можете определить компаратор, но поскольку дженерики не работают с примитивами, он не будет работать с int[] .

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

С помощью List<Integer> и Integer[] это проще:

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

С int[] это более беспорядочно. Вы можете использовать IntStream и вставить его с помощью boxed() в Stream<Integer> . Но тогда вы получите снижение производительности, но если вы не имеете дело с огромными массивами или не используете их в критической части приложения, это не будет проблемой.

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

Комментарии:

1. Arrays.asList(...) в этом случае работает, потому что параметры автоматически разделяются на целые числа по отдельности, но если вы это сделаете Arrays.asList(intArray) , вы получите List<int[]> .

Ответ №3:

Это немного объектно-ориентированное решение, которое не требует памяти для копирования массива в список, не требует распаковки списка обратно в массив, и вам не нужно изобретать какие-либо алгоритмы сортировки:

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

Если у вас язык Commons, он намного чище:

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

Компаратор из другого ответа, ((Integer i1, Integer i2) -> Math.abs(i2) - Math.abs(i1)) , — это просто версия lambda, если она приведена здесь. Если у вас Java 8 , не стесняйтесь использовать любой из них.

Комментарии:

1. Однако для каждого сравнения требуется упаковка и распаковка элементов.

2. / машет руками, / бормочет что-то о jit, escape-анализе и о том, как это должно быть быстро когда-нибудь.

Ответ №4:

Просто отсортируйте входные данные 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);
}
  

Выводит

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

Требуется импорт:

 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;