2011-02-01 14 views
48

Załóżmy, że użytkownik wprowadzić tablicę, na przykład:Uzyskaj indeksy tablicy po sortowaniu?

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

którą znał długość nim

tablica index byłoby:

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

Teraz, po sortowaniu go za pomocą Arrays.sort(Array);

newArray będzie następująca:

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

i newIndex będą:

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

Problem: w jaki sposób mogę znaleźć newIndex z tablicy wejściowej?

Z góry dziękuję

+0

Podobne na http://stackoverflow.com/questions/4839915/sorting-a-list-based-on-another-lists-values-java/4839994#4839994, ale o wiele jaśniej zdefiniowane. – maaartinus

Odpowiedz

70

Nie sortuj tablicy na początek. Posortuj tablicę indeksów, przechodząc do komparatora, który porównuje wartości, używając ich do indeksów. W rezultacie sortowania uzyskuje się newIndex, a przejście od posortowanej tablicy rzeczywistych elementów jest banalne.

Wprawdzie to znaczy sortowania tablicę liczb całkowitych w niestandardowy sposób - co też oznacza, używając Integer[] i biblioteki standardowej Java lub 3rd biblioteki Strona, która interfejs „IntComparator”, który może być używany w połączeniu z sort(int[], IntComparator) rodzaj metody.

EDYCJA: Okay, oto przykładowy komparator. Dla uproszczenia założę, że chcesz sortować tylko "oryginalną" tablicę łańcuchów ... i nie będę zawracał sobie głowy testami nieważności.

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

Można by użyć go w ten sposób:

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

Jednym ze sposobów można to zrobić, aby owinąć oryginalny indeks i nazwę kraju, do osobnej klasy. Następnie posortuj tablicę na podstawie nazw. W ten sposób Twoje oryginalne indeksy zostaną zachowane.

+0

czy mógłbyś podać przykład, proszę? –

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

Teraz ponad map.values ​​iterator(), aby pobrać indeksów w kolejności sortowania, a ponad map.keySet(), aby uzyskać ciągi lub nad map.entrySet(), aby uzyskać ciąg indeks par .

+3

To nie działa z powodu duplikatów. SortedMultimap nie pomoże tutaj. – maaartinus

+0

@maaartinus Można go użyć do pracy z mapą TreeMap >. Najpierw dodaj wszystkie ciągi do mapy z pustymi listami, a następnie przetestuj oryginalną listę i dodaj indeksy do list elementów mapy. –

+0

Następnie należy po prostu powtórzyć wartości i wstawić element dla każdego indeksu na liście ... Byłby stabilny. –

1

co przychodzi na pierwszy rzut oka jest na mapie ich jak tego

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

a następnie posortować je według wartości like that czym można poznać ich indeksy i wartości (kluczowe wartości) po prostu wydrukować mapę

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

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

    System.out.println(key + " " + value); 
} 
+1

Dlaczego nie używasz pętli foreach? Dlaczego robisz to wolniej za pomocą keySet() i wyszukiwania zamiast entrySet()? Dlaczego wyprowadzasz wartości zamiast tworzyć metodę, która może być dalej używana? – maaartinus

+0

Najpierw przychodzi mi do głowy. Oczywiście, możesz zrobić w ten sposób –

10

zwięzły sposób osiągnięcia tego z Java 8 Stream 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

Jak sortujesz to w odwrotnej/malejącej kolejności? Jeśli tablica ma podwójny typ danych. – kingspp

+0

Używałbyś metody compareTo na górze Double –

2

Zrobiłem na podstawie kodu @ Skeeta.Myślę, że to trochę więcej OOPie. Nie wiem.

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

zamiast klasy implementującej sortowania i indeksowania o kod komparatora dla różnych obiektów najbliższych, obiekty w oryginalnej matrycy musi implementować porównywalnym interfejs. Wydaje się, że wiele interesujących obiektów ma naturalną kolejność i już wdrożono interfejs porównywalny.

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

razie konieczności scenariusz wielokrotnie sortowania prymitywny pływak lub int tablice wartości dodatnich, to wówczas sposób jak poniżej daje znacznie lepsza (x3 ~ x4) Szybkość porównaniu do użycia porównawczych:

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! Sprytna sztuczka polegająca na włożeniu klucza w dolne bity sortowanej wartości. – stolsvik

Powiązane problemy