2011-02-01 22 views
48

は、たとえば、ユーザーが列を入力したとします、私はそれソート後に配列のインデックスを取得しますか?

の長さを知っていた

Array = {France, Spain, France, France, Italy, Spain, Spain, Italy} 

index配列は次のようになります。

index = {0, 1, 2, 3, 4, 5, 6, 7} 

を今、使用してそれをソートした後Arrays.sort(Array);

newArrayは次のようになります。

newArray = {France, France, France, Italy, Italy, Spain, Spain, Spain} 

newIndexは次のようになります。

newIndex = {0, 2, 3, 4, 7, 1, 5, 6} 

問題がある:私は入力配列からnewIndexを見つけることができますか?

ありがとうございます事前にありがとうございます

+0

http://stackoverflow.com/questions/4839915/sorting-a-list-based-on-another-lists-values-java/4839994#4839994よりはっきりと定義されています。 – maaartinus

答えて

70

最初に配列をソートしないでください。インデックス配列をソートして、を使用して値を比較するコンパレータを渡し、配列にというインデックスを付けます。したがって、ソートの結果としてnewIndexになります。そこから実際のアイテムの並べ替えられた配列に行くのは簡単です。カスタムの方法で整数の配列をソートする意味

確かに - Integer[]と標準のJavaライブラリ、またはsort(int[], IntComparator)と組み合わせて使用​​することができる「IntComparator」インターフェースを持つサードパーティのライブラリを使用してのいずれかを意味タイプのメソッド。

EDIT:これはコンパレータの例です。わかりやすくするために、私はあなたが単に "元の"文字列の配列をソートしたいと思っています...そして、私はnullityテストを気にしません。

public class ArrayIndexComparator implements Comparator<Integer> 
{ 
    private final String[] array; 

    public ArrayIndexComparator(String[] array) 
    { 
     this.array = array; 
    } 

    public Integer[] createIndexArray() 
    { 
     Integer[] indexes = new Integer[array.length]; 
     for (int i = 0; i < array.length; i++) 
     { 
      indexes[i] = i; // Autoboxing 
     } 
     return indexes; 
    } 

    @Override 
    public int compare(Integer index1, Integer index2) 
    { 
     // Autounbox from Integer to int to use as array indexes 
     return array[index1].compareTo(array[index2]); 
    } 
} 

あなたはこのようにそれを使用したい:あなたがこれを行うことが

String[] countries = { "France", "Spain", ... }; 
ArrayIndexComparator comparator = new ArrayIndexComparator(countries); 
Integer[] indexes = comparator.createIndexArray(); 
Arrays.sort(indexes, comparator); 
// Now the indexes are in appropriate order. 
1

一つの方法は、別々のクラスに元の索引と国の名前をラップすることです。その後、名前に基づいて配列をソートします。これにより、元のインデックスが保持されます。

+0

お願いしますか? –

4
TreeMap<String,Int> map = new TreeMap<String,Int>(); 
for(int i : indexes) { 
    map.put(stringarray[i], i); 
} 

map.valuesの反復子()文字列を取得するために)(ソート順で、かつmap.keySet上のインデックスを取得するために、またはmap.entrySetオーバー()文字列のインデックス・ペアを取得します。一見すると何が来るのか

+3

これは重複しているために機能しません。 SortedMultimapはここでは役に立ちません。 – maaartinus

+0

@maaartinus TreeMap >のマップで作業することができます。まず空のリストを使ってすべての文字列をマップに追加してから、元のリストを繰り返して地図アイテムリストにインデックスを追加します。 –

+0

次に、単純に値を反復し、リスト内の各インデックスの要素を挿入します。安定しています。 –

1

ちょうどマップ

Iterator mapIterator = map.keySet().iterator(); 

while (mapIterator .hasNext()) { 
    String key = mapIterator.next().toString(); 
    String value = map.get(key).toString(); 

    System.out.println(key + " " + value); 
} 
を印刷すること

Map <Integer, String> map = new HashMap<Integer, String>(); 
map.put(0, "France"); 
map.put(1, "Spain"); 
map.put(2, "France"); 

のようにそれらをマッピングし、値like thatによってそれらを並べ替えた後、あなたはそのインデックスと値(キー、値)を知ることができています

+1

なぜforeach-loopを使用しないのですか? keySet()とentrySet()の代わりにルックアップを使って、なぜそれを遅くするのですか?メソッドを作る代わりに値を出力するのはなぜですか?これはさらに使用できますか? – maaartinus

+0

まずは私の心に来る。もちろん、そのようにすることができます –

10

のJava 8ストリームAPIでこれを達成するための簡潔な方法、

final String[] strArr = {"France", "Spain", "France"}; 
int[] sortedIndices = IntStream.range(0, strArr.length) 
       .boxed().sorted((i, j) -> strArr[i].compareTo(strArr[j])) 
       .mapToInt(ele -> ele).toArray(); 
+0

どのように逆順/降順で並べ替えるのですか?配列がdoubleデータ型の場合 – kingspp

+0

Doubleの上にcompareToメソッドを使用します –

2

私は@ Skeetのコードに基づいて以下を作った。私はもう少しOOPieだと思う。私は知らないよ。代わりに来る別のオブジェクトのコンパレータコードを有する分類および索引付けを実装するクラスの

public static <T extends Comparable<T>> List<Integer> sortIndex(List<T> in) { 
    ArrayList<Integer> index = new ArrayList<>(); 
    for (int i = 0; i < in.size(); i++) { 
     index.add(i); 
    } 

    Collections.sort(index, new Comparator<Integer>() { 
     @Override 
     public int compare(Integer idx1, Integer idx2) { 
      return in.get(idx1).compareTo(in.get(idx2)); 
     } 
    }); 

    return index; 
} 

、元の配列内のオブジェクトは、Comparableインタフェースを実装しなければなりません。関心のある多くのオブジェクトには自然順序付けがあり、既にComparableインターフェイスが実装されているようです。

public static void main(String[] args) { 

    List<Integer> a1 = new ArrayList<>(Arrays.asList(2, 3, 9, 4, 1)); 
    // Just pass in the list to have its indexes sorted by the natural ordering 
    List<Integer> idx = sortIndex(a1); 

    List<Double> a2 = new ArrayList<>(Arrays.asList(1.0, 5.3, 5.2, -3.1, 0.3)); 
    idx = sortIndex(a2); 

    List<numBits> a3 = new ArrayList<>(); 
    for (int i = 0; i < 10; i++) { 
     a3.add(new numBits(i)); 
    } 

    // If you need to sort the indexes of your own object, you must implement 
    // the Comparable Interface. 
    idx = sortIndex(a3); 
} 

static class numBits implements Comparable<numBits> { 
    private int a; 

    public numBits(int i) { 
     a = i; 
    } 

    public String toString() { 
     return Integer.toString(a); 
    } 

    // Sort by the total number of bits in the number. 
    @Override 
    public int compareTo(numBits that) { 
     if (Integer.bitCount(this.a) < Integer.bitCount(that.a)) 
      return -1; 
     if (Integer.bitCount(this.a) > Integer.bitCount(that.a)) 
      return 1; 
     return 0; 
    } 
} 
1

繰り返し正の値とプリミティブフロートまたはINTアレイをソートのシナリオを有する場合には、以下のような方法は、任意のコンパレータを使用する場合に比べはるかに優れ(X3〜X4)速度が得られる:

同様
long time = System.currentTimeMillis(); 
for (int i = 0; i < iters; i++) {   
    float[] array = RandomUtils.randomFloatArray(-1, 1, 3000); 
    long[] valueKeyPairs = new long[array.length]; 
    for (int j = 0; j < array.length; ++j) { 
     valueKeyPairs[j] = (((long) Float.floatToIntBits(array[j])) << 32) | (j & 0xffffffffL); 
    } 
    Arrays.sort(valueKeyPairs); 
    /**Then use this to retrieve the original value and index*/ 
    //long l = valueKeyPairs[j]; 
    //float value = Float.intBitsToFloat((int) (l >> 32)); 
    //int index = (int) (l); 
} 
long millis = System.currentTimeMillis() - time; 
+1

Nifty!ソートされる値の下位ビットにキーをスティックするかわいいトリックです。 – stolsvik

関連する問題