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


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

7 54

7 ответов:

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

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[], создает копию массива, выполняет сортировку, а затем копирует отсортированные данные поверх оригинала.

Как насчет использования потоков (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
    );

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

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

    };

и теперь вы можете сделать сортировку по этому списку обертки с помощью пользовательского компаратора.

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

можно использовать IntArrays.quickSort(array, comparator) из библиотеки fastutil.

вот вспомогательный метод для выполнения этой работы.

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

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

(конечно, вы можете сделать это с автоупаковка / распаковка, но я туда не пойду, это некрасиво)

затем, вот вспомогательный метод для сортировки массива 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]

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

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

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.It на самом деле зависит на ситуацию.Я больше не могу думать ни о каких ситуациях.Может быть, Александру может дать больше примеров, так как он говорит, он хочет использовать компаратор для массива.