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.

Ankur
quelle
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);
Paul Tomblin
quelle
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
92

So etwas sollte funktionieren und den ArrayList-Konstruktor aufrufen, der eine Sammlung akzeptiert :

List theList = new ArrayList(coll);
Jack Leow
quelle
Schön und einfach.
James Gawron
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);
Erel Segal-Halevi
quelle
21

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

coll.stream().collect(Collectors.toList())
Eyal Ofri
quelle
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 ) );
OscarRyz
quelle
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());
}
Nathan Perrier
quelle
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.

Vlasec
quelle
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));
Arhus
quelle