Jak przekonwertować kolekcję na listę?

294

Korzystam TreeBidiMapz biblioteki kolekcji Apache . Chcę posortować to według wartości, które są doubles.

Moja metoda polega na pobraniu jednej Collectionz wartości za pomocą:

Collection coll = themap.values();

Co oczywiście działa dobrze.

Główne pytanie: Chcę teraz wiedzieć, jak mogę przekonwertować / rzutować (nie jestem pewien, co jest poprawne) collna plik, Listaby można go było posortować?

Zamierzam następnie iterować posortowany Listobiekt, który powinien być w porządku, i uzyskać odpowiednie klucze z TreeBidiMap( themap), używając themap.getKey(iterator.next())miejsca, w którym iterator będzie nad listą doubles.

Ankur
źródło
4
Możesz uniknąć tego kroku, bezpośrednio używając jakiegoś SortedMap, więc wpisy są w naturalnej kolejności używanych kluczy. Własna TreeMap w Javie implementuje SortedMap.
Axel Knauf
TreeBidiMapjest OrderedMap, zamówienie powinno być w porządku. Sortowanie wymagane w pytaniu dotyczy wartości, a nie kluczy.
Vlasec

Odpowiedzi:

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

Jak mówi poniżej Erel Segal Halevi, jeśli coll jest już listą, możesz pominąć krok pierwszy. Ale to zależy od wewnętrznych elementów TreeBidiMap.

List list;
if (coll instanceof List)
  list = (List)coll;
else
  list = new ArrayList(coll);
Paul Tomblin
źródło
4
Należy zauważyć, że oba podejścia mają różne skutki uboczne: rzutowanie kolekcji na listę, a następnie sortowanie posortuje również oryginalną kolekcję; tworzenie kopii nie będzie.
Barney
Takie podejście znacznie obniża wydajność, jeśli jest używane wielokrotnie. Zobacz moją odpowiedź na rozwiązanie, które działa w locie i obejmuje kolekcję niestandardową.
Vlasec,
Nie rozwiązuje to przypadku, gdy map.values ​​() zwraca kolekcję „klasy wewnętrznej”. Kompilator zgłasza, że ​​Kolekcje.sort (Lista <T>) nie akceptuje Kolekcje.sort (Lista <Klasa wewnętrzna>). Rozwiązaniem było nawet użycie: List <InnerClass> list = map.values ​​(). Stream (). Collect (Collectors.toList ())
Pereira
92

Coś takiego powinno działać, wywołując konstruktor ArrayList, który pobiera kolekcję:

List theList = new ArrayList(coll);
Jack Leow
źródło
Ładne i proste.
James Gawron
33

Myślę, że odpowiedź Paula Tomblina może być marnotrawstwem, jeśli coll jest już listą, ponieważ utworzy nową listę i skopiuje wszystkie elementy. Jeśli coll zawiera wiele elementów, może to zająć dużo czasu.

Moja sugestia to:

List list;
if (coll instanceof List)
  list = (List)coll;
else
  list = new ArrayList(coll);
Collections.sort(list);
Erel Segal-Halevi
źródło
21

Wierzę, że możesz to tak napisać:

coll.stream().collect(Collectors.toList())
Eyal Ofri
źródło
Lepszy sposób na obejście castingu
Stackee007
Świetny! To rozwiązało moją sprawę. Moja map.values ​​() zwraca kolekcję „klasy wewnętrznej”. Kompilator zgłosił, że Kolekcje.sort (Lista <T>) nie akceptuje Kolekcje.sort (Lista <Klasa wewnętrzna>).
Pereira
nie działało w moim przypadku użycia w Androidzie. wymaga minimalnego api 24
ansh sachdeva
8
Collections.sort( new ArrayList( coll ) );
OscarRyz
źródło
Brakuje odniesienia do dostępu do ArrayList?
Zach Scrivena
@Zach: mmhh good point. Wiedziałem, że mam powód, aby oznaczyć to jako CW. BTW, ans Paul jest tym jedynym. Nie wiem, dlaczego ma tylko moją ultrafiolet.
OscarRyz
4

@Kunigami: Myślę, że możesz się mylić co do newArrayListmetody Guavy . Nie sprawdza, czy Iterable jest typem List, i po prostu zwraca daną Listę taką, jaka jest. To zawsze tworzy nową listę:

@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
źródło
Jak to nie jest więcej głosowane? Odpowiedź Kunigami jest niepoprawna (o ile zakłada o podstawowej implementacji).
GreenieMeanie
0

To, czego żądasz, jest dość kosztowną operacją, upewnij się, że nie musisz tego robić często (np. W cyklu).

W przeciwnym razie możesz utworzyć własną kolekcję. Wymyśliłem taki, który ma twoje TreeBidiMapi TreeMultisetpod maską. Wdrażaj tylko to, czego potrzebujesz i dbaj o integralność danych.

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

W ten sposób masz posortowane Multiset wrócił z values(). Jednak jeśli potrzebujesz, aby była to lista (np. Potrzebujesz tablicy podobnej do tablicyget(index) ), musisz wymyślić coś bardziej złożonego.

Vlasec
źródło
keySet()i values()są widokami oryginału Map, więc kiedy zostaną zmodyfikowane, należy również zmodyfikować podkład Map, twoje rozwiązanie tego nie obsługuje
Lino
-4

Oto nieoptymalne rozwiązanie jako jedna linijka:

Collections.list(Collections.enumeration(coll));
Arhus
źródło