Wie konvertiere ich eine Sammlung in eine Liste?


294

Ich verwende TreeBidiMapaus der Apache Collections- Bibliothek. Ich möchte dies nach den Werten sortieren, die sind doubles.

Meine Methode besteht darin, einen Collectionder Werte abzurufen , indem ich:

Collection coll = themap.values();

Was natürlich gut funktioniert.

Haupt Frage: Ich möchte jetzt wissen , wie ich umwandeln kann / cast (nicht sicher , was richtig ist) collin ein Listso es sortiert werden können?

Ich beabsichtige dann, über das sortierte ListObjekt zu iterieren , das in Ordnung sein sollte, und die entsprechenden Schlüssel von TreeBidiMap( themap) zu erhalten, indem themap.getKey(iterator.next())ich verwende, wo sich der Iterator über der Liste von befindet doubles.


4
Möglicherweise möchten Sie diesen Schritt vermeiden, indem Sie direkt eine Art SortedMap verwenden, damit die Einträge in der natürlichen Reihenfolge der verwendeten Schlüssel angezeigt werden. Javas eigene TreeMap implementiert SortedMap.
Axel Knauf

TreeBidiMapist eine OrderedMap, die Bestellung sollte ok sein. Die in der Frage erforderliche Sortierung erfolgt nach Werten, nicht nach Schlüsseln.
Vlasec

Antworten:


470
List list = new ArrayList(coll);
Collections.sort(list);

Wie Erel Segal Halevi weiter unten sagt, können Sie Schritt eins überspringen, wenn coll bereits eine Liste ist. Dies würde jedoch von den Interna von TreeBidiMap abhängen.

List list;
if (coll instanceof List)
  list = (List)coll;
else
  list = new ArrayList(coll);

4
Nur um zu beachten, dass die beiden Ansätze unterschiedliche Nebenwirkungen haben: Wenn Sie die Sammlung in eine Liste umwandeln und dann sortieren, wird auch die ursprüngliche Sammlung sortiert. Erstellen einer Kopie wird nicht.
Barney

Dieser Ansatz verschlechtert die Leistung erheblich, wenn er wiederholt verwendet wird. In meiner Antwort finden Sie eine Lösung, die im laufenden Betrieb funktioniert und eine benutzerdefinierte Sammlung umfasst.
Vlasec

Dies löst den Fall nicht, wenn map.values ​​() eine "innere Klasse" -Sammlung zurückgibt. Der Compiler meldet, dass Collections.sort (List <T>) Collections.sort (List <InnerClass>) nicht akzeptiert. Die Lösung war sogar zu verwenden: List <InnerClass> list = map.values ​​(). Stream (). Collect (Collectors.toList ())
Pereira


33

Ich denke, Paul Tomblins Antwort kann verschwenderisch sein, falls coll bereits eine Liste ist, da dadurch eine neue Liste erstellt und alle Elemente kopiert werden. Wenn coll viele Elemente enthält, kann dies lange dauern.

Mein Vorschlag ist:

List list;
if (coll instanceof List)
  list = (List)coll;
else
  list = new ArrayList(coll);
Collections.sort(list);

21

Ich glaube, Sie können es als solches schreiben:

coll.stream().collect(Collectors.toList())

Besserer Weg, um Casting zu
umgehen

Großartig! Dies löste meinen Fall. Meine map.values ​​() gibt eine "innere Klasse" -Sammlung zurück. Der Compiler hat gemeldet, dass Collections.sort (List <T>) Collections.sort (List <InnerClass>) nicht akzeptiert.
Pereira

hat für meinen Anwendungsfall in Android nicht funktioniert. erfordert mindestens api 24
ansh sachdeva

8
Collections.sort( new ArrayList( coll ) );

Fehlt eine Referenz für den Zugriff auf ArrayList?
Zach Scrivena

@ Zach: mmhh guter Punkt. Ich wusste, dass es einen Grund für mich gab, dies als CW zu markieren. Übrigens ist Pauls Ans derjenige. Ich weiß nicht, warum er nur mein UV hat.
OscarRyz

4

@ Kunigami: Ich denke, Sie können sich über Guavas newArrayListMethode irren . Es wird nicht geprüft, ob es sich bei der Iterable um einen Listentyp handelt, und es wird einfach die angegebene Liste unverändert zurückgegeben. Es wird immer eine neue Liste erstellt:

@GwtCompatible(serializable = true)
public static <E> ArrayList<E> newArrayList(Iterable<? extends E> elements) {
  checkNotNull(elements); // for GWT
  // Let ArrayList's sizing logic work, if possible
  return (elements instanceof Collection)
      ? new ArrayList<E>(Collections2.cast(elements))
      : newArrayList(elements.iterator());
}

Wie wird das nicht mehr hochgestimmt? Kunigamis Antwort ist falsch (soweit es um die zugrunde liegende Implementierung geht).
GreenieMeanie

0

Was Sie anfordern, ist eine ziemlich kostspielige Operation. Stellen Sie sicher, dass Sie dies nicht oft tun müssen (z. B. in einem Zyklus).

Andernfalls können Sie eine benutzerdefinierte Sammlung erstellen. Ich habe mir eine ausgedacht, die deine TreeBidiMapund TreeMultisetunter der Haube hat. Implementieren Sie nur das, was Sie benötigen, und achten Sie auf die Datenintegrität.

class MyCustomCollection implements Map<K, V> {
    TreeBidiMap<K, V> map;
    TreeMultiset<V> multiset;
    public V put(K key, V value) {
        removeValue(map.put(key, value));
        multiset.add(value);
    }
    public boolean remove(K key) {
        removeValue(map.remove(key));
    }
    /** removes value that was removed/replaced in map */
    private removeValue(V value) {
        if (value != null) {
            multiset.remove(value);
        }
    }
    public Set keySet() {
        return map.keySet();
    }
    public Multiset values() {
        return multiset;
    }
    // many more methods to be implemented, e.g. count, isEmpty etc.
}

Auf diese Weise haben Sie eine sortierte Multiset Rückgabe von values(). Wenn Sie jedoch eine Liste benötigen (z. B. die Array-ähnliche get(index)Methode), müssen Sie etwas Komplexeres erfinden.


keySet()und values()sind Ansichten zum Original Map. Wenn sie also geändert werden, muss auch der Hintergrund Mapgeändert werden. Ihre Lösung unterstützt dies nicht
Lino

-4

Hier ist eine suboptimale Lösung als Einzeiler:

Collections.list(Collections.enumeration(coll));
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.