source

커스텀 컴퍼레이터를 사용하여 int 배열을 정렬하려면 어떻게 해야 합니까?

factcode 2022. 11. 26. 13:52
반응형

커스텀 컴퍼레이터를 사용하여 int 배열을 정렬하려면 어떻게 해야 합니까?

커스텀 컴퍼레이터를 사용하여 int 배열을 정렬해야 하는데 자바 라이브러리는 비교기와의 int 정렬 기능을 제공하지 않습니다(비교기는 오브젝트와만 사용할 수 있습니다).쉬운 방법이 없을까요?

입력 배열의 유형을 변경할 수 없는 경우 다음을 수행합니다.

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

이것은 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
    );

Fastutil 라이브러리에서 사용할 수 있습니다.

어레이를 복사하지 않는 경우(매우 큰 경우 등), 래퍼를 작성할 수 있습니다.List<Integer>다음과 같이 사용할 수 있습니다.

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

    };

이제 커스텀 비교기를 사용하여 이 래퍼 목록에서 정렬할 수 있습니다.

외부 라이브러리는 필요 없습니다.

Integer[] input = Arrays.stream(arr).boxed().toArray(Integer[]::new);
Arrays.sort(input, (a, b) -> b - a); // reverse order
return Arrays.stream(input).mapToInt(Integer::intValue).toArray();

int 어레이를 integer로 변환한 후 를 사용합니다(어레이에서는 자동 박스가 동작할 가능성이 있기 때문에 첫 번째 단계만 필요합니다).

Java 8:

Arrays.stream(new int[]{10,4,5,6,1,2,3,7,9,8}).boxed().sorted((e1,e2)-> e2-e1).collect(Collectors.toList());

성능을 높이고 도중에 생성되는 개체 수를 줄이려는 경우 이클립스 컬렉션의 구현을 고려해 보십시오.

커스텀을 사용합니다.IntComparator이 기능은 기본 요소에서 작동하므로 박스가 필요하지 않습니다.

다음은 작업을 수행하기 위한 도우미 방법입니다.

우선 Comparator 인터페이스가 필요합니다. Comparator는 기본 요소를 지원하지 않기 때문입니다.

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]

정렬 코드는 Arrays.sort(int[])에서 가져온 것으로 소규모 어레이용으로 최적화된 버전만 사용했습니다.실제 실장에서는 내부 메서드의 소스 코드를 참조하는 것이 좋습니다.sort1(int[], offset, length)[ Arrays ]클래스에서 사용합니다.

나는 원시형 자체의 비교기를 최대한 사용하려고 했다.결국 나는 대조군을 속일 방법이 없다는 결론을 내렸다.이것이 나의 실장입니다.

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

}

@로마: 좋은 예라고는 할 수 없지만, 당신이 물어봤기 때문에 이런 생각이 들었다.배열에서 절대값만을 기준으로 숫자를 정렬한다고 가정합니다.

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

다른 예로는 100보다 큰 숫자만 정렬하는 경우가 있습니다.사실 상황에 따라 다르죠.더 이상 상황이 생각나지 않아요.Alexandru가 int 배열에 비교기를 사용하는 것을 원하기 때문에 더 많은 예를 들어줄 수 있을지도 모릅니다.

여기 복싱/언박스를 사용하지 않고도 효과적인 코드(원래는 Timsort는 아니지만 잘 작동합니다)가 있습니다.테스트에서는 Collections를 사용하는 것보다 3~4배 더 빨리 작동합니다.배열 주위에 목록 래퍼를 사용하여 정렬합니다.

// This code has been contributed by 29AjayKumar 
// from: https://www.geeksforgeeks.org/sort/

static final int sortIntArrayWithComparator_RUN = 32; 

// this function sorts array from left index to  
// to right index which is of size atmost RUN  
static void sortIntArrayWithComparator_insertionSort(int[] arr, IntComparator comparator, int left, int right) { 
    for (int i = left + 1; i <= right; i++)  
    { 
        int temp = arr[i]; 
        int j = i - 1; 
        while (j >= left && comparator.compare(arr[j], temp) > 0)
        { 
            arr[j + 1] = arr[j]; 
            j--; 
        } 
        arr[j + 1] = temp; 
    } 
} 

// merge function merges the sorted runs  
static void sortIntArrayWithComparator_merge(int[] arr, IntComparator comparator, int l, int m, int r) { 
    // original array is broken in two parts  
    // left and right array  
    int len1 = m - l + 1, len2 = r - m; 
    int[] left = new int[len1]; 
    int[] right = new int[len2]; 
    for (int x = 0; x < len1; x++)  
    { 
        left[x] = arr[l + x]; 
    } 
    for (int x = 0; x < len2; x++)  
    { 
        right[x] = arr[m + 1 + x]; 
    } 

    int i = 0; 
    int j = 0; 
    int k = l; 

    // after comparing, we merge those two array  
    // in larger sub array  
    while (i < len1 && j < len2)  
    { 
        if (comparator.compare(left[i], right[j]) <= 0)
        { 
            arr[k] = left[i]; 
            i++; 
        } 
        else 
        { 
            arr[k] = right[j]; 
            j++; 
        } 
        k++; 
    } 

    // copy remaining elements of left, if any  
    while (i < len1) 
    { 
        arr[k] = left[i]; 
        k++; 
        i++; 
    } 

    // copy remaining element of right, if any  
    while (j < len2)  
    { 
        arr[k] = right[j]; 
        k++; 
        j++; 
    } 
} 

// iterative sort function to sort the  
// array[0...n-1] (similar to merge sort)  
static void sortIntArrayWithComparator(int[] arr, IntComparator comparator) { sortIntArrayWithComparator(arr, lIntArray(arr), comparator); }
static void sortIntArrayWithComparator(int[] arr, int n, IntComparator comparator) { 
    // Sort individual subarrays of size RUN  
    for (int i = 0; i < n; i += sortIntArrayWithComparator_RUN)  
    { 
        sortIntArrayWithComparator_insertionSort(arr, comparator, i, Math.min((i + 31), (n - 1))); 
    } 

    // start merging from size RUN (or 32). It will merge  
    // to form size 64, then 128, 256 and so on ....  
    for (int size = sortIntArrayWithComparator_RUN; size < n; size = 2 * size)  
    { 
          
        // pick starting point of left sub array. We  
        // are going to merge arr[left..left+size-1]  
        // and arr[left+size, left+2*size-1]  
        // After every merge, we increase left by 2*size  
        for (int left = 0; left < n; left += 2 * size)  
        { 
              
            // find ending point of left sub array  
            // mid+1 is starting point of right sub array  
            int mid = Math.min(left + size - 1, n - 1);
            int right = Math.min(left + 2 * size - 1, n - 1); 

            // merge sub array arr[left.....mid] &  
            // arr[mid+1....right]  
            sortIntArrayWithComparator_merge(arr, comparator, left, mid, right); 
        } 
    } 
}

static int lIntArray(int[] a) {
  return a == null ? 0 : a.length;
}

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

언급URL : https://stackoverflow.com/questions/3699141/how-to-sort-an-array-of-ints-using-a-custom-comparator

반응형