2011-02-01 122 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 2011-02-01 05:49:01

回答

70

不要對數組開始排序。對索引數組進行排序,傳入一個比較器,將比較值通過作爲索引進行比較。所以你最終得到newIndex作爲排序的結果,並且從那裏到實際項目的排序數組很簡單。不可否認,這意味着以自定義方式對整數數組進行排序 - 這意味着使用Integer[]和標準Java庫,或者具有「IntComparator」接口的第三方庫,它可以與sort(int[], IntComparator)類型的方法。

編輯:好的,這裏是一個示例比較。爲了簡單起見,我假設你只想對一個「原始」字符串進行排序......而且我不打擾無效性測試。

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

你能舉個例子嗎? – 2011-02-01 05:36:50

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 2011-02-01 05:51:33

+0

@maaartinus可以使用TreeMap >的地圖。首先,您將所有字符串添加到地圖中,並且列表爲空,然後遍歷原始列表並將索引添加到地圖項目列表中。 – 2015-10-10 21:26:37

+0

然後,您只需遍歷值併爲列表中的每個索引插入一個元素即可。它會很穩定。 – 2015-10-10 21:27:15

1

乍一看會給出映射它們就像

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

,然後通過價值like that對它們進行排序,然後你就可以知道他們的索引和值(鍵,值)只打印地圖

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

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

    System.out.println(key + " " + value); 
} 
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(); 
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

如果具有重複排序基本float或具有正值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;