Comment convertir une collection en liste?

294

J'utilise TreeBidiMapde la bibliothèque Apache Collections . Je veux trier cela sur les valeurs qui sont doubles.

Ma méthode consiste à récupérer une Collectiondes valeurs en utilisant:

Collection coll = themap.values();

Ce qui fonctionne naturellement bien.

Question principale: je veux maintenant savoir comment convertir / convertir (je ne sais pas lequel est correct) collen un Listafin qu'il puisse être trié?

J'ai ensuite l'intention d'itérer sur l' Listobjet trié , qui devrait être en ordre et d'obtenir les clés appropriées de TreeBidiMap( themap) en utilisant themap.getKey(iterator.next())où l'itérateur sera sur la liste de doubles.

Ankur
la source
4
Vous voudrez peut-être éviter cette étape en utilisant directement une sorte de SortedMap, afin que les entrées soient dans l'ordre naturel des clés utilisées. Le propre TreeMap de Java implémente SortedMap.
Axel Knauf
TreeBidiMapest un OrderedMap, la commande doit être correcte. Le tri requis dans la question concerne les valeurs, pas les clés.
Vlasec

Réponses:

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

Comme Erel Segal Halevi le dit ci-dessous, si coll est déjà une liste, vous pouvez ignorer la première étape. Mais cela dépendrait des éléments internes de TreeBidiMap.

List list;
if (coll instanceof List)
  list = (List)coll;
else
  list = new ArrayList(coll);
Paul Tomblin
la source
4
Juste pour noter qu'il y a différents effets secondaires aux deux approches: couler la collection dans une liste puis trier triera également la collection d'origine; la création d'une copie ne le sera pas.
Barney
Cette approche dégrade considérablement les performances si elle est utilisée à plusieurs reprises. Voir ma réponse pour une solution qui fonctionne à la volée, elle implique une collection personnalisée.
Vlasec
Cela ne résout pas le cas lorsque map.values ​​() renvoie une collection "classe interne". Le compilateur signale que Collections.sort (List <T>) n'accepte pas Collections.sort (List <InnerClass>). La solution était même d'utiliser: List <InnerClass> list = map.values ​​(). Stream (). Collect (Collectors.toList ())
Pereira
92

Quelque chose comme ça devrait fonctionner, en appelant le constructeur ArrayList qui prend une collection:

List theList = new ArrayList(coll);
Jack Leow
la source
Agréable et simple.
James Gawron
33

Je pense que la réponse de Paul Tomblin peut être inutile si coll est déjà une liste, car cela créera une nouvelle liste et copiera tous les éléments. Si coll contient de nombreux éléments, cela peut prendre du temps.

Ma suggestion est:

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

Je pense que vous pouvez l'écrire comme tel:

coll.stream().collect(Collectors.toList())
Eyal Ofri
la source
Meilleure façon de contourner le casting
Stackee007
Génial! Cela a résolu mon cas. My map.values ​​() renvoie une collection de "classe interne". Le compilateur a signalé que Collections.sort (List <T>) n'accepte pas Collections.sort (List <InnerClass>).
Pereira
n'a pas fonctionné pour mon cas d'utilisation dans Android. requiert un minimum de 24 api
ansh sachdeva
8
Collections.sort( new ArrayList( coll ) );
OscarRyz
la source
Vous manquez une référence pour accéder à ArrayList?
Zach Scrivena
@Zach: mmhh bon point. Je savais qu'il y avait une raison pour que je marque cela comme CW. BTW Paul's ans est celui-là. Je ne sais pas pourquoi il n'a que mon uv.
OscarRyz
4

@Kunigami: Je pense que vous vous trompez peut-être sur la newArrayListméthode de Guava . Il ne vérifie pas si l'itérable est un type de liste et renvoie simplement la liste donnée telle quelle. Il crée toujours une nouvelle liste:

@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
la source
Comment cela n'est-il pas davantage voté? La réponse de Kunigami est incorrecte (pour autant qu'elle suppose sur l'implémentation sous-jacente).
GreenieMeanie
0

Ce que vous demandez est une opération assez coûteuse, assurez-vous que vous n'avez pas besoin de le faire souvent (par exemple dans un cycle).

Sinon, vous pouvez créer une collection personnalisée. Je suis venu avec un qui a votre TreeBidiMapet TreeMultisetsous le capot. N'implémentez que ce dont vous avez besoin et faites attention à l'intégrité des données.

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 cette façon, vous avez un tri de Multiset retour values(). Cependant, si vous avez besoin que ce soit une liste (par exemple, vous avez besoin de la get(index)méthode de type tableau ), vous devrez inventer quelque chose de plus complexe.

Vlasec
la source
keySet()et values()sont des vues par rapport à l'original Map, donc lorsqu'elles sont modifiées, le support Mapdoit également être modifié, votre solution ne le prend pas en charge
Lino
0

Java 14 introduit List#copyOfqui retourne une liste non modifiable tout en préservant l'ordre:

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

Voici une solution sous-optimale en une ligne:

Collections.list(Collections.enumeration(coll));
Arhus
la source