How to sort an array of ints using a custom comparator?

0 votes
asked Sep 13, 2010 by alexandru

I need to sort an array of ints using a custom comparator, but Java's library doesn't provide a sort function for ints with comparators (comparators can be used only with objects). Is there any easy way to do this?

7 Answers

0 votes
answered Sep 13, 2010 by riduidel

By transforming your int array into an Integer one and then using public static <T> void Arrays.sort(T[] a, Comparator<? super T> c) (the first step is only needed as I fear autoboxing may bot work on arrays).

0 votes
answered Sep 13, 2010 by jon-freedman

If you can't change the type of your input array the following will work:

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

This uses ArrayUtils from the commons-lang project to easily convert between int[] and Integer[], creates a copy of the array, does the sort, and then copies the sorted data over the original.

0 votes
answered Sep 13, 2010 by sean-patrick-floyd

Here is a helper method to do the job.

First of all you'll need a new Comparator interface, as Comparator doesn't support primitives:

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

(You could of course do it with autoboxing / unboxing but I won't go there, that's ugly)

Then, here's a helper method to sort an int array using this comparator:

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

And here is some client code. A stupid comparator that sorts all numbers that consist only of the digit '9' to the front (again sorted by size) and then the rest (for whatever good that is):

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

Output:

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

The sort code was taken from Arrays.sort(int[]), and I only used the version that is optimized for tiny arrays. For a real implementation you'd probably want to look at the source code of the internal method sort1(int[], offset, length) in the Arrays class.

0 votes
answered Sep 13, 2010 by emil

I tried maximum to use the comparator with primitive type itself. At-last i concluded that there is no way to cheat the comparator.This is my implementation.

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: I can't say that this is a good example but since you asked this is what came to my mind. Suppose in an array you want to sort number's just based on their absolute value.

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

Another example can be like you want to sort only numbers greater than 100.It actually depends on the situation.I can't think of any more situations.Maybe Alexandru can give more examples since he say's he want's to use a comparator for int array.

0 votes
answered Sep 9, 2015 by user3669782

How about using streams (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();

Or in-place:

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
    );
0 votes
answered Sep 11, 2015 by user1460736

If you don't want to copy the array (say it is very large), you might want to create a wrapper List that can be used in a sort:

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

    };

And now you can do a sort on this wrapper List using a custom comparator.

0 votes
answered Sep 15, 2017 by leventov

You can use IntArrays.quickSort(array, comparator) from fastutil library.

Welcome to Q&A, where you can ask questions and receive answers from other members of the community.
Website Online Counter

...