2010-09-13 28 views
50

Özel bir karşılaştırıcı kullanarak bir dizi sıralamayı sıralamalıyım, ancak Java'nın kitaplığı, karşılaştırıcılarla birlikte ints için bir sıralama işlevi sağlamaz (karşılaştırıcılar yalnızca nesnelerle kullanılabilir). Bunu yapmanın kolay bir yolu var mı?Özel bir karşılaştırıcı kullanarak bir dizi init nasıl sıralanır?

+0

Diziyi yalnızca azalan sırada sıralamak mı yoksa daha karmaşık bir şey yapmak mı istiyorsunuz? – Roman

+0

Daha karmaşık bir şey. Int değerini mutlak değer olarak bir anahtar olarak sıralamak istiyorum. – Alexandru

+14

Java'nın özgün bir karşılaştırıcı ile ilkel 'ın'yi sıralayamadığına inanamıyorum! – HRJ

cevap

40

şu çalışacaktır:

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

Bu kolayca int[] ve Integer[] arasında dönüştürmek için commons-lang projesinden ArrayUtils kullanır bir kopyasını oluşturur dizi, sıralama yapar ve sonra sıralanmış verileri orijinalin üzerine kopyalar.

+1

Neden dizi -> liste -> dizi dönüştürmek yerine Arrays.sort'u kullanmıyorsunuz? – nanda

+0

İyi nokta, güncelledim, commons-primitives ile oynuyordu, ama aslında yararlı bir şey yapmadı –

+0

Ben commons-lang hakkında bilmiyordum. Bahşiş için teşekkürler. – Alexandru

0

İşte bu işi yapmak için yardımcı bir yöntem.

Comparator olarak yeni bir karşılaştırıcı arayüzü gerekir her şeyden

Öncelikle primitifler desteklemez:

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

(Elbette kutudan çıkarma Autoboxing/bile yaparım ama orada gitmeyecek,

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

Ve burada bazı istemci kod şudur: o

Sonra burada bu karşılaştırıcı kullanarak bir int dizi sıralamak için bir yardımcı yöntemdir) çirkin. (Olduğunu ne olursa olsun iyiliği için) sadece rakam '9' (yine boyutuna göre sıralı olarak) öne oluşur tüm numaraları ve sonra gerisini sıralayan bir aptal karşılaştırıcı:

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

Çıktı:

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

Sıralama kodu Arrays.sort(int[])'dan alındı ​​ve yalnızca küçük diziler için en iyileştirilmiş sürümü kullandım. Gerçek bir uygulama için, Arrays sınıfındaki iç yöntem sort1(int[], offset, length) kaynak koduna bakmak isteyebilirsiniz.

+3

Arrays.sort() Quicksort kullanıyor gibi görünüyor koduna bakarken önerilen sıralama ekleme sıralama kullanıyor gibi görünüyor. Asimptotik olarak daha yavaş olmaz mıydı? –

0

Karşılaştırıcıyı ilkel türün kendisiyle kullanmak için maksimum çaba harcadım. Sonunda karşılaştırıcıyı aldatmanın bir yolu olmadığına karar verdim. Bu benim uygulamam.

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: Bu aklıma gelen budur istedi beri bu iyi bir örnek olduğunu söyleyebiliriz ama olamaz. Numaraları yalnızca mutlak değerlerine göre sıralamak istediğiniz bir dizide varsayalım.

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

Eğer 100.It aslında o 's istiyoruz say'nın beri daha fazla örnek verebiliriz artık situations.Maybe Alexandru düşünemiyorum situation.I bağlıdır daha tek sayılar daha sıralamak istiyorum gibi başka örnek olabilir int dizisi için bir karşılaştırıcı kullanmak.

+0

@Emil: Biraz kapalı için üzgünüm, ama sadece merak ediyorum, bana bir dizi tamsayıyı sıralamak için kullandığınız bir karşılaştırıcı örneğini gösterir misiniz? İade işareti * (i1 - i2); 'işaret 'istenen siparişe bağlı olarak -1 veya +1 dışında hiçbir uygulama hayal edemiyorum. – Roman

+0

@Emil: Aslında, az önce gördüğüm uygulamanın büyük olasılıkla kırılmış olduğunu (ilk başta uzun süre yayınlanması gerekir), ancak bağlamda önemi yoktur. – Roman

+0

Artan ve azalan sıralama sıralamasından başka bir tamsayı karşılaştırması gerekli değil mi? – Emil

14

Akışları kullanma hakkında (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-yerinde:

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

IntStream üzerinde sıralayamadığımız (IntComparator) hata veriyor. – Trejkaz

+5

Ters sıra için '(a, b) -> b - a' kullanmayın. Bu karşılaştırıcı taşabilir. Comparator.reverseOrder() 'ın varlığına dikkat edin… – Holger

+0

Tamamen potansiyel taşma kaçırdı. Cevabı uyarladı. Teşekkürler Holger! – user3669782

3

Eğer dizi kopyalamak istemiyorsanız (çok büyük olduğunu söylemek), içeri kullanılabilecek bir sarıcı listesi oluşturmak isteyebilirsiniz sıralama:

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

    }; 

Artık özel bir karşılaştırıcı kullanarak bu sarmalayıcı Listesinde bir sıralama yapabilirsiniz.

+0

Bunu kabul edilen yanıttan çok daha iyi seviyorum. Dizi içeriğini kopyalamaya veya dönüştürmeye gerek yok, yalnızca Listelerin özel uygulamasından yararlanın. – OB1

+1

@ OB1: düzgün görünüyor, ancak standart 'sort 'uygulaması tüm listeyi bir diziye kopyalar, sıralar ve geri yazar. Ve bu liste 'RandomAccess' işaretlemesini uygulayamadığından, geri yazma sadece 'set' yerine bir' ListIterator 'kullanıyor olacaktır. – Holger

+0

Vay, Holger kopya hakkında haklı. Bunu kontrol etmeyi bile düşünmedim, çünkü hiç kimsenin bir kopyasını yapmak için yeterince cesur olmayacağını varsaydım. – user1460736

İlgili konular