¿Cómo convertir una colección a la lista?

294

Estoy usando TreeBidiMapde la biblioteca Apache Collections . Quiero ordenar esto en los valores que son doubles.

Mi método es recuperar uno Collectionde los valores usando:

Collection coll = themap.values();

Que naturalmente funciona bien.

Principal Pregunta: Ahora quiero saber cómo puedo convertir / molde (no estoy seguro que es correcto) collen una Listmanera que puede ser ordenada?

Luego tengo la intención de iterar sobre el Listobjeto ordenado , que debe estar en orden y obtener las claves apropiadas de TreeBidiMap( themap) usando themap.getKey(iterator.next())donde el iterador estará sobre la lista de doubles.

Ankur
fuente
44
Es posible que desee evitar este paso utilizando directamente algún tipo de SortedMap, por lo que las entradas están en el orden natural de las teclas que se utilizan. El propio TreeMap de Java implementa SortedMap.
Axel Knauf
TreeBidiMapes un OrderedMap, el orden debe estar bien. La clasificación requerida en la pregunta está en valores, no en claves.
Vlasec

Respuestas:

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

Como dice Erel Segal Halevi a continuación, si coll ya es una lista, puede omitir el paso uno. Pero eso dependería de lo interno de TreeBidiMap.

List list;
if (coll instanceof List)
  list = (List)coll;
else
  list = new ArrayList(coll);
Paul Tomblin
fuente
44
Solo para tener en cuenta que los dos enfoques tienen diferentes efectos secundarios: convertir la colección en una lista y luego ordenarla también ordenará la colección original; crear una copia no lo hará.
Barney
Este enfoque degrada el rendimiento en gran medida si se usa repetidamente. Vea mi respuesta para una solución que funciona sobre la marcha, implica una colección personalizada.
Vlasec
Esto no resuelve el caso cuando map.values ​​() devuelve una colección de "clase interna". El compilador informa que Collections.sort (List <T>) no acepta Collections.sort (List <InnerClass>). La solución fue incluso usar: List <InnerClass> list = map.values ​​(). Stream (). Collect (Collectors.toList ())
Pereira
92

Algo como esto debería funcionar, llamando al constructor ArrayList que toma una colección:

List theList = new ArrayList(coll);
Jack Leow
fuente
Agradable y simple
James Gawron
33

Creo que la respuesta de Paul Tomblin puede ser un desperdicio en caso de que coll ya sea una lista, porque creará una nueva lista y copiará todos los elementos. Si el coll contiene muchos elementos, esto puede llevar mucho tiempo.

Mi sugerencia es:

List list;
if (coll instanceof List)
  list = (List)coll;
else
  list = new ArrayList(coll);
Collections.sort(list);
Erel Segal-Halevi
fuente
21

Creo que puedes escribirlo así:

coll.stream().collect(Collectors.toList())
Eyal Ofri
fuente
Mejor manera de evitar el casting
Stackee007
¡Excelente! Esto resolvió mi caso. My map.values ​​() devuelve una colección de "clase interna". El compilador informó que Collections.sort (List <T>) no acepta Collections.sort (List <InnerClass>).
Pereira
no funcionó para mi caso de uso en Android. requiere mínimo API 24
Ansh Sachdeva
8
Collections.sort( new ArrayList( coll ) );
OscarRyz
fuente
¿Falta una referencia para acceder a ArrayList?
Zach Scrivena
@Zach: mmhh buen punto. Sabía que había una razón para marcar esto como CW. Por cierto, la respuesta de Paul es la indicada. No sé por qué solo tiene mi uv.
OscarRyz
4

@Kunigami: Creo que puede estar equivocado sobre el newArrayListmétodo de Guava . No comprueba si el Iterable es un tipo de Lista y simplemente devuelve la Lista dada como está. es siempre crea una nueva 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());
}
Nathan Perrier
fuente
¿Cómo no se vota más? La respuesta de Kunigami es incorrecta (en la medida en que supone sobre la implementación subyacente).
GreenieMeanie
0

Lo que solicita es una operación bastante costosa, asegúrese de no tener que hacerlo con frecuencia (por ejemplo, en un ciclo).

De lo contrario, puede crear una colección personalizada. Se me ocurrió uno que tiene tu TreeBidiMapy TreeMultisetdebajo del capó. Implemente solo lo que necesita y preocúpese por la integridad de los datos.

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

De esta manera, usted tiene una ordenados Multiset de regresar de values(). Sin embargo, si necesita que sea una lista (por ejemplo, necesita el get(index)método tipo matriz ), tendría que inventar algo más complejo.

Vlasec
fuente
keySet()y values()son vistas al original Map, por lo que cuando se modifican el respaldo también Mapdebe modificarse, su solución no es compatible con esto
Lino
0

Se introdujo Java 14 List#copyOfque devuelve la Lista no modificable mientras se conserva el orden:

List<Integer> list = List.copyOf(coll);
Aniket Sahrawat
fuente
-4

Aquí hay una solución subóptima como una línea:

Collections.list(Collections.enumeration(coll));
Arhus
fuente