Как отсортировать массив с помощью специализированного компаратора?

Мне нужно отсортировать массив ints с помощью специализированного компаратора, но библиотека Java не предоставляет функцию сортировки для int с компараторами (компараторы могут использоваться только с объектами). Есть ли простой способ сделать это?

Ответ 1

Если вы не можете изменить тип вашего входного массива, будет работать следующее:

final int[] data = new int[] { 5, 4, 2, 1, 3 };
final Integer[] sorted = ArrayUtils.toObject(data);
Arrays.sort(sorted, new Comparator<Integer>() {
    public int compare(Integer o1, Integer o2) {
        // Intentional: Reverse order for this demo
        return o2.compareTo(o1);
    }
});
System.arraycopy(ArrayUtils.toPrimitive(sorted), 0, data, 0, sorted.length);

Это использует ArrayUtils из проекта commons-lang, чтобы легко конвертировать между int[] и Integer[], создает копию массив, выполняет сортировку и затем копирует отсортированные данные по оригиналу.

Ответ 2

Как использовать потоки (Java 8)?

int[] ia = {99, 11, 7, 21, 4, 2};
ia = Arrays.stream(ia).
    boxed().
    sorted((a, b) -> b.compareTo(a)). // sort descending
    mapToInt(i -> i).
    toArray();

Или на месте:

int[] ia = {99, 11, 7, 21, 4, 2};
System.arraycopy(
        Arrays.stream(ia).
            boxed().
            sorted((a, b) -> b.compareTo(a)). // sort descending
            mapToInt(i -> i).
            toArray(),
        0,
        ia,
        0,
        ia.length
    );

Ответ 3

Если вы не хотите копировать массив (скажем, очень большой), вам может понадобиться создать список-оболочку, который можно использовать в сортировке:

final int[] elements = {1, 2, 3, 4};
List<Integer> wrapper = new AbstractList<Integer>() {

        @Override
        public Integer get(int index) {
            return elements[index];
        }

        @Override
        public int size() {
            return elements.length;
        }

        @Override
        public Integer set(int index, Integer element) {
            int v = elements[index];
            elements[index] = element;
            return v;
        }

    };

И теперь вы можете сделать сортировку в этом списке-оболочке с помощью специального компаратора.

Ответ 4

Преобразуя массив int в Integer, а затем используя public static <T> void Arrays.sort(T[] a, Comparator<? super T> c) (первый шаг нужен только, поскольку я боюсь, что автобоксинг может бот работает с массивами).

Ответ 6

Вот вспомогательный метод для выполнения задания.

Прежде всего вам понадобится новый интерфейс Comparator, поскольку Comparator не поддерживает примитивы:

public interface IntComparator{
    public int compare(int a, int b);
}

(Конечно, вы могли бы сделать это с помощью autoboxing/unboxing, но я не поеду туда, это уродливо)

Затем, здесь вспомогательный метод для сортировки массива int с использованием этого компаратора:

public static void sort(final int[] data, final IntComparator comparator){
    for(int i = 0; i < data.length + 0; i++){
        for(int j = i; j > 0
            && comparator.compare(data[j - 1], data[j]) > 0; j--){
            final int b = j - 1;
            final int t = data[j];
            data[j] = data[b];
            data[b] = t;
        }
    }
}

И вот какой-то клиентский код. Глупый компаратор, который сортирует все числа, которые состоят только из цифры "9" на фронт (снова сортируются по размеру), а затем остальные (для любого хорошего):

final int[] data =
    { 4343, 544, 433, 99, 44934343, 9999, 32, 999, 9, 292, 65 };
sort(data, new IntComparator(){

    @Override
    public int compare(final int a, final int b){
        final boolean onlyNinesA = this.onlyNines(a);
        final boolean onlyNinesB = this.onlyNines(b);
        if(onlyNinesA && !onlyNinesB){
            return -1;
        }
        if(onlyNinesB && !onlyNinesA){
            return 1;
        }

        return Integer.valueOf(a).compareTo(Integer.valueOf(b));
    }

    private boolean onlyNines(final int candidate){
        final String str = String.valueOf(candidate);
        boolean nines = true;
        for(int i = 0; i < str.length(); i++){
            if(!(str.charAt(i) == '9')){
                nines = false;
                break;
            }
        }
        return nines;
    }
});

System.out.println(Arrays.toString(data));

Вывод:

[9, 99, 999, 9999, 32, 65, 292, 433, 544, 4343, 44934343]

Код сортировки был взят из Arrays.sort(int []), и я использовал только версию, оптимизированную для крошечных массивов, Для реальной реализации вы, вероятно, захотите посмотреть исходный код внутреннего метода sort1(int[], offset, length) в классе Arrays.

Ответ 7

Я попытался максимально использовать компаратор с самим примитивным типом. Наконец я пришел к выводу, что нет возможности обмануть компаратора. Это моя реализация.

public class ArrSortComptr {
    public static void main(String[] args) {

         int[] array = { 3, 2, 1, 5, 8, 6 };
         int[] sortedArr=SortPrimitiveInt(new intComp(),array);
         System.out.println("InPut "+ Arrays.toString(array));
         System.out.println("OutPut "+ Arrays.toString(sortedArr));

    }
 static int[] SortPrimitiveInt(Comparator<Integer> com,int ... arr)
 {
    Integer[] objInt=intToObject(arr);
    Arrays.sort(objInt,com);
    return intObjToPrimitive(objInt);

 }
 static Integer[] intToObject(int ... arr)
 {
    Integer[] a=new Integer[arr.length];
    int cnt=0;
    for(int val:arr)
      a[cnt++]=new Integer(val);
    return a;
 }
 static int[] intObjToPrimitive(Integer ... arr)
 {
     int[] a=new int[arr.length];
     int cnt=0;
     for(Integer val:arr)
         if(val!=null)
             a[cnt++]=val.intValue();
     return a;

 }

}
class intComp implements Comparator<Integer>
{

    @Override //your comparator implementation.
    public int compare(Integer o1, Integer o2) {
        // TODO Auto-generated method stub
        return o1.compareTo(o2);
    }

}

@Roman: Я не могу сказать, что это хороший пример, но, поскольку вы спросили об этом, мне пришло в голову. Предположим, что в массиве вы хотите отсортировать номер только по их абсолютной величине.

Integer d1=Math.abs(o1);
Integer d2=Math.abs(o2);
return d1.compareTo(d2);

Другой пример может быть похож на то, что вы хотите сортировать только числа, превышающие 100. Фактически это зависит от ситуации. Я не могу больше думать о ситуациях. Возможно, Александру может привести больше примеров, поскольку он говорит, что хочет использовать компаратор для массива int.