Convertir l'ensemble en liste sans créer de nouvelle liste


503

J'utilise ce code pour convertir un Seten un List:

Map<String, List<String>> mainMap = new HashMap<>();

for (int i=0; i < something.size(); i++) {
  Set<String> set = getSet(...); //returns different result each time
  List<String> listOfNames = new ArrayList<>(set);
  mainMap.put(differentKeyName, listOfNames);
}

Je veux éviter de créer une nouvelle liste à chaque itération de la boucle. Est-ce possible?


1
Je connais un moyen de convertir l'ensemble en liste comme dans Q. Je veux éviter de créer une nouvelle liste chaque fois en boucle.
Muhammad Imran Tariq

4
Pourquoi ne pouvez-vous pas simplement ajouter l'ensemble à mainList? Pourquoi avez-vous besoin de convertir l'ensemble en liste?
DagR

1
Avez-vous l'intention de créer une liste <Liste <? >>
Hiery Nomus

5
Tu ne peux pas. Votre question incarne une contradiction dans les termes.
Marquis de Lorne

Réponses:


803

Vous pouvez utiliser la méthode List.addAll () . Il accepte une collection comme argument et votre ensemble est une collection.

List<String> mainList = new ArrayList<String>();
mainList.addAll(set);

EDIT: comme répondre à l'édition de la question.
Il est facile de voir que si vous voulez avoir un Mapavec Lists comme valeurs, afin d'avoir k valeurs différentes, vous devez créer k listes différentes.
Ainsi: Vous ne pouvez pas éviter de créer ces listes du tout, les listes devront être créées.

Solution possible:
déclarez votre Mapcomme un Map<String,Set>ou à la Map<String,Collection>place, et insérez simplement votre ensemble.


1
désolé, il était mainMap pas la liste. voir la question
Muhammad Imran Tariq

@imrantariq: differentKeyNamechange chaque itération? Voulez-vous réellement something.size()différentes valeurs possibles dans vos cartes? Il est facile de voir qu'une carte avec des klistes en tant que valeurs doit créer au moins des klistes.
2012

@imrantariq: et vous voulez une liste différente pour chaque clé que je suppose?
2012

@imrantariq: Ce que vous demandez est impossible. lire ma modification pour plus de détails.
2012

Il renverra NullPointerException au cas où l'ensemble est nul.
w35l3y

411

Utilisez le constructeur pour le convertir:

List<?> list = new ArrayList<?>(set);

21
Il a spécifiquement dit qu'il voulait éviter cela.
mapeters

3
@mook Irrelevant, car son exigence n'est pas réalisable.
Marquis de Lorne

16
@EJP alors sa réponse doit dire que, au lieu de simplement déclarer quelque chose que l'OP n'a pas demandé sans aucune explication.
mapeters

il l'évite, ce constructeur utilise System.arrayCopy, qui fait des copies superficielles, ce qui signifie qu'il ne copie que les références des objets dans le tableau utilisé pour créer la liste. Si vous comparez les deux collections, vous verrez qu'elles contiennent toutes les deux des références aux mêmes objets.
Gubatron

Cela ne fonctionne pas réellement sur Android. Une raison pourquoi?
kbluue

84

Également à partir de la bibliothèque Guava Collect, vous pouvez utiliser newArrayList(Collection):

Lists.newArrayList([your_set])

Ce serait très similaire à la réponse précédente de amit , sauf que vous n'avez pas besoin de déclarer (ou d'instancier) un listobjet.


1
Si vous utilisez de la goyave, c'est pratique
vsingh

6
Bien que vous n'appeliez pas directement le constructeur, cette méthode appelle toujours le ArrayListconstructeur.
glen3b

Si je ne déclare pas de liste, comment puis-je utiliser la liste créée?
Koray Tugay

@KorayTugay, vous extrayez bien Lists.newArrayList ([votre_set]) dans une variable (locale ou globale). Par exemple: List <Foo> fooList = Lists.newArrayList (setOfFoo) Mais votre question est erronée. Si vous créez une liste, elle est au moins implicitement déclarée (sinon explicitement).
chaiyachaiya

1
Vous devinez pourquoi cela a fait cette méthode? Cela ne semble pas mieux que new ArrayList<>([your_set]).
DavidS

49

Nous pouvons utiliser un seul liner en Java 8:

List<String> list = set.stream().collect(Collectors.toList());

Voici un petit exemple:

public static void main(String[] args) {
        Set<String> set = new TreeSet<>();
        set.add("A");
        set.add("B");
        set.add("C");
        List<String> list = set.stream().collect(Collectors.toList());
}

7
Pour plus de lisibilité, ce n'est pas recommandé. Par exemple, IntelliJ suggère "new ArrayList <> (set)" et répertorie plus de 20 échantillons de code similaires avec peuvent être remplacés de la même manière.
rrhrg

exactement! @rrhrg qui est meilleur pour les performances si nous utilisons set.parallelStream ()?
gaurav

31

la solution la plus simple

Je voulais un moyen très rapide de convertir mon jeu en liste et de le renvoyer, donc en une ligne, je l'ai fait

 return new ArrayList<Long>(mySetVariable);

1
C'est également ce que suggère IntelliJ IDEA au lieu de l'API Streams.
Ben

6

Vous pouvez utiliser ce changement d'une ligne: Arrays.asList(set.toArray(new Object[set.size()]))

Map<String, List> mainMap = new HashMap<String, List>();

for(int i=0; i<something.size(); i++){
  Set set = getSet(...); 
  mainMap.put(differentKeyName, Arrays.asList(set.toArray(new Object[set.size()])));
}  

Taille corrigée car le nouvel objet [0] ne contiendra qu'un seul élément mais le nouvel objet [set.size ()] contiendra toutes les valeurs
rajadilipkolli

5

Je ferais :

Map<String, Collection> mainMap = new HashMap<String, Collection>();

for(int i=0; i<something.size(); i++){
  Set set = getSet(...); //return different result each time
  mainMap.put(differentKeyName,set);
}

5

Comme il n'a pas été mentionné jusqu'à présent, à partir de Java 10, vous pouvez utiliser la nouvelle copyOfméthode d'usine:

List.copyOf(set);

Depuis le Javadoc :

Renvoie une liste non modifiable contenant les éléments de la collection donnée, dans son ordre d'itération.


3

Java 8 offre la possibilité d'utiliser des flux et vous pouvez obtenir une liste Set<String> setStringsous la forme:

List<String> stringList = setString.stream().collect(Collectors.toList());

Bien que l'implémentation interne fournisse à ce jour une instance de ArrayList:

public static <T>
    Collector<T, ?, List<T>> toList() {
        return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
                                   (left, right) -> { left.addAll(right); return left; },
                                   CH_ID);
    }

mais JDK ne le garantit pas. Comme mentionné ici :

Il n'y a aucune garantie sur le type, la mutabilité, la sérialisation ou la sécurité des threads de la liste retournée; si davantage de contrôle sur la liste retournée est requis, utilisez toCollection (fournisseur).

Si vous voulez toujours être sûr, vous pouvez demander une instance spécifiquement comme:

List<String> stringArrayList = setString.stream()
                     .collect(Collectors.toCollection(ArrayList::new));

2

Je crée une staticméthode simple :

public static <U> List<U> convertSetToList(Set<U> set)
{
    return new ArrayList<U>(set);
}

... ou si vous souhaitez définir le type de liste, vous pouvez utiliser:

public static <U, L extends List<U>> List<U> convertSetToList(Set<U> set, Class<L> clazz) throws InstantiationException, IllegalAccessException
{
    L list = clazz.newInstance();
    list.addAll(set);
    return list;
}

2

Récemment, j'ai trouvé ceci:

ArrayList<T> yourList = Collections.list(Collections.enumeration(yourSet<T>));

1
Pouvez-vous développer ou élaborer davantage à ce sujet?
Vandal

Collections.list () crée une nouvelle liste de tableaux:public static <T> ArrayList<T> list(Enumeration<T> e) { ArrayList<T> l = new ArrayList<>(); while (e.hasMoreElements()) l.add(e.nextElement()); return l; }
Artem Lukanin

2

Par souci d'exhaustivité ...

Supposons que vous souhaitiez vraiment traiter les Mapvaleurs comme des Lists, mais que vous souhaitiez éviter de les copier Setà Listchaque fois.

Par exemple, vous appelez peut-être une fonction de bibliothèque qui crée un Set, mais vous passez votre Map<String, List<String>>résultat à une fonction de bibliothèque (mal conçue mais hors de vos mains) qui ne prend que Map<String, List<String>>, même si vous savez d'une manière ou d'une autre que les opérations qu'il fait avec le Lists sont également applicables à tout Collection(et donc à tout Set). Et pour une raison quelconque, vous devez éviter la surcharge de vitesse / mémoire de la copie de chaque ensemble dans une liste.

Dans ce cas de super niche, en fonction du comportement (peut-être inconnu) dont la fonction de bibliothèque a besoin dans vos Lists, vous pourrez peut-être créer une List vue sur chaque ensemble. Notez que cela est intrinsèquement dangereux (car les exigences de la fonction de bibliothèque de chacun Listpourraient vraisemblablement changer à votre insu), donc une autre solution devrait être préférée. Mais voici comment vous le feriez.

Vous devez créer une classe qui implémente l' Listinterface, prend un Setdans le constructeur et affecte cet ensemble à un champ, puis utilise cette interne Setpour implémenter l' ListAPI (dans la mesure du possible et souhaitée).

Notez que certains comportements List que vous ne pourrez tout simplement pas imiter sans stocker les éléments en tant que List, et certains comportements que vous ne pourrez imiter que partiellement. Encore une fois, cette classe n'est pas un remplacement sûr pour les Lists en général. En particulier, si vous savez que le cas d'utilisation nécessite des opérations liées à l'index ou une MUTATION List, cette approche irait très vite vers le sud.

public class ListViewOfSet<U> implements List<U> {
    private final Set<U> wrappedSet;
    public ListViewOfSet(Set<U> setToWrap) { this.wrappedSet = setToWrap; }

    @Override public int size() { return this.wrappedSet.size(); }
    @Override public boolean isEmpty() { return this.wrappedSet.isEmpty(); }
    @Override public boolean contains(Object o) { return this.wrappedSet.contains(o); }
    @Override public java.util.Iterator<U> iterator() { return this.wrappedSet.iterator(); }
    @Override public Object[] toArray() { return this.wrappedSet.toArray(); }
    @Override public <T> T[] toArray(T[] ts) { return this.wrappedSet.toArray(ts); }
    @Override public boolean add(U e) { return this.wrappedSet.add(e); }
    @Override public boolean remove(Object o) { return this.wrappedSet.remove(o); }
    @Override public boolean containsAll(Collection<?> clctn) { return this.wrappedSet.containsAll(clctn); }
    @Override public boolean addAll(Collection<? extends U> clctn) { return this.wrappedSet.addAll(clctn); }
    @Override public boolean addAll(int i, Collection<? extends U> clctn) { throw new UnsupportedOperationException(); }
    @Override public boolean removeAll(Collection<?> clctn) { return this.wrappedSet.removeAll(clctn); }
    @Override public boolean retainAll(Collection<?> clctn) { return this.wrappedSet.retainAll(clctn); }
    @Override public void clear() { this.wrappedSet.clear(); }
    @Override public U get(int i) { throw new UnsupportedOperationException(); }
    @Override public U set(int i, U e) { throw new UnsupportedOperationException(); }
    @Override public void add(int i, U e) { throw new UnsupportedOperationException(); }
    @Override public U remove(int i) { throw new UnsupportedOperationException(); }
    @Override public int indexOf(Object o) { throw new UnsupportedOperationException(); }
    @Override public int lastIndexOf(Object o) { throw new UnsupportedOperationException(); }
    @Override public ListIterator<U> listIterator() { throw new UnsupportedOperationException(); }
    @Override public ListIterator<U> listIterator(int i) { throw new UnsupportedOperationException(); }
    @Override public List<U> subList(int i, int i1) { throw new UnsupportedOperationException(); }
}

...
Set<String> set = getSet(...);
ListViewOfSet<String> listOfNames = new ListViewOfSet<>(set);
...

C'est en fait la seule réponse qui résout réellement le problème posé dans la question!
Lii

Vous pouvez l'implémenter assez facilement en étendant AbstractList
Lii

1

J'ai trouvé que cela fonctionnait bien et utile pour créer une liste à partir d'un ensemble.

ArrayList < String > L1 = new ArrayList < String > ();
L1.addAll(ActualMap.keySet());
for (String x: L1) {
    System.out.println(x.toString());
}

-15
Map<String, List> mainMap = new HashMap<String, List>();

for(int i=0; i<something.size(); i++){
  Set set = getSet(...); //return different result each time
  mainMap.put(differentKeyName, new ArrayList(set));
}

11
Vous n'avez pas évité de créer la liste. Ce code est très similaire à l'exemple de votre question.
Taylor

2
Mais cela ne répond pas à votre quezon, pas qu'il y ait une réponse.
Marquis de Lorne
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.