tags:

views:

168

answers:

4

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?

+2  A: 

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

Riduidel
+5  A: 

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) {
        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.

Jon Freedman
Why don't you use Arrays.sort instead of converting array -> list -> array?
nanda
Good point, I've updated, was playing around with commons-primitives, but didn't actually do anything useful
Jon Freedman
I didn't know about commons-lang. Thanks for the tip.
Alexandru
+1  A: 

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.

seanizer
A: 

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.

Emil
@Emil: sorry for a little offtop, but I'm just curious, could you please show me an example of comparator you've used to sort an array of integers? I just can't imagine none implementation except for `return sign * (i1 - i2);` where `sign` is -1 or +1 depending on desirable order.
Roman
@Emil: actually, implementation I've just shown is probably broken (ints should be casted to long at first) but it doesn't matter in the context.
Roman
Do you mean to say that a comparator for integer is not required other than ascending and descending order sort?
Emil
@Emil: almost yes, but I said that only I can't imagine another case.
Roman
@Roman:I appended a sample to the answer.I don't know if this was what you expected.
Emil
@Emil: ok, situations are seldom, but let it be.. thanks for your responses.
Roman