Come convertire una raccolta in elenco?


294

Sto usando TreeBidiMapdalla libreria Collezioni di Apache . Voglio ordinare questo in base ai valori che sono doubles.

Il mio metodo è recuperare uno Collectiondei valori usando:

Collection coll = themap.values();

Che naturalmente funziona bene.

Domanda principale: ora voglio sapere come posso convertire / trasmettere (non sono sicuro di quale sia corretto) collin un Listmodo che possa essere ordinato?

Ho quindi intenzione di iterare Listsull'oggetto ordinato , che dovrebbe essere in ordine e ottenere le chiavi appropriate da TreeBidiMap( themap) usando themap.getKey(iterator.next())dove l'iteratore sarà sulla lista di doubles.


4
Potresti voler evitare questo passaggio utilizzando direttamente una sorta di SortedMap, quindi le voci sono nell'ordine naturale delle chiavi utilizzate. La TreeMap di Java implementa SortedMap.
Axel Knauf,

TreeBidiMapè un OrderedMap, l'ordine dovrebbe essere ok. L'ordinamento richiesto nella domanda si basa sui valori, non sulle chiavi.
Vlasec,

Risposte:


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

Come dice Erel Segal Halevi di seguito, se coll è già un elenco, puoi saltare il primo passaggio. Ma ciò dipenderebbe dall'interno di TreeBidiMap.

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

4
Solo per notare che ci sono diversi effetti collaterali nei due approcci: lanciare la raccolta in un elenco e quindi ordinare ordinerà anche la raccolta originale; la creazione di una copia non lo farà.
Barney,

Questo approccio degrada notevolmente le prestazioni se utilizzato ripetutamente. Vedi la mia risposta per una soluzione che funziona al volo, implica una raccolta personalizzata.
Vlasec,

Questo non risolve il caso quando map.values ​​() restituisce una raccolta di "classe interna". Il compilatore segnala che Collections.sort (Elenco <T>) non accetta Collections.sort (Elenco <InnerClass>). La soluzione era persino quella di usare: List <InnerClass> list = map.values ​​(). Stream (). Collect (Collectors.toList ())
Pereira,


33

Penso che la risposta di Paul Tomblin possa essere dispendiosa nel caso in cui coll sia già un elenco, perché creerà un nuovo elenco e copierà tutti gli elementi. Se coll contiene molti elementi, ciò potrebbe richiedere molto tempo.

Il mio consiglio è:

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

21

Credo che tu possa scriverlo come tale:

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

Modo migliore per aggirare il casting
Stackee007,

Grande! Questo ha risolto il mio caso. My map.values ​​() restituisce una raccolta "classe interna". Il compilatore ha riferito che Collections.sort (Elenco <T>) non accetta Collections.sort (Elenco <InnerClass>).
Pereira,

non ha funzionato per il mio caso d'uso in Android. richiede minimo api 24
ansh sachdeva il

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

Manca un riferimento per accedere a ArrayList?
Zach Scrivena,

@Zach: mmhh buon punto. Sapevo che c'era un motivo per me di contrassegnarlo come CW. BTW Paul's ans è quello. Non so perché abbia solo il mio uv.
OscarRyz

4

@Kunigami: penso che potresti sbagliare sul newArrayListmetodo di Guava . Non controlla se l'Iterable è un tipo Elenco e restituisce semplicemente l'Elenco dato così com'è. E ' sempre crea una nuova lista:

@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());
}

In che modo non viene più votato? La risposta di Kunigami è errata (per quanto presuppone l'implementazione sottostante).
GreenieMeanie,

0

Ciò che richiedi è un'operazione piuttosto costosa, assicurati di non doverlo fare spesso (ad es. In un ciclo).

Altrimenti, puoi creare una raccolta personalizzata. Ne ho trovato uno che ha il tuo TreeBidiMape TreeMultisetsotto il cofano. Implementa solo ciò di cui hai bisogno e preoccupati dell'integrità dei dati.

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

In questo modo, hai un reso ordinato Multiset da values(). Tuttavia, se hai bisogno che sia un elenco (ad esempio, hai bisogno del get(index)metodo simile a un array ), dovresti inventare qualcosa di più complesso.


keySet()e values()sono viste all'originale Map, quindi quando vengono modificati anche il supporto Mapdeve essere modificato, la tua soluzione non supporta questo
Lino

-4

Ecco una soluzione non ottimale come one-liner:

Collections.list(Collections.enumeration(coll));
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.