Как отсортировать массив int с помощью пользовательского компаратора?
Мне нужно отсортировать массив ints с помощью пользовательского компаратора, но библиотека Java не предоставляет функцию сортировки для ints с компараторами (компараторы могут использоваться только с объектами). Есть ли простой способ сделать это?
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 на самом деле зависит на ситуацию.Я больше не могу думать ни о каких ситуациях.Может быть, Александру может дать больше примеров, так как он говорит, он хочет использовать компаратор для массива.