Мне нужно отсортировать массив 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)
(первый шаг нужен только, поскольку я боюсь, что автобоксинг может бот работает с массивами).
Ответ 5
Вы можете использовать IntArrays.quickSort(array, comparator)
из библиотеки fastutil.
Ответ 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.