Converti Imposta in elenco senza creare un nuovo elenco


503

Sto usando questo codice per convertire un Setin 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);
}

Voglio evitare di creare un nuovo elenco in ogni iterazione del ciclo. È possibile?


1
Conosco un modo per convertire set in list come in Q. Voglio evitare di creare un nuovo elenco ogni volta in loop.
Muhammad Imran Tariq,

4
Perché non puoi semplicemente aggiungere il set a mainList? Perché è necessario convertire il set in un elenco?
DagR,

1
Hai intenzione di creare un Elenco <Elenco <? >>
Hiery Nomus il

5
Non puoi. La tua domanda incarna una contraddizione in termini.
Marchese di Lorne,

Risposte:


803

È possibile utilizzare il metodo List.addAll () . Accetta una raccolta come argomento e il tuo set è una raccolta.

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

MODIFICA: come risposta alla modifica della domanda.
È facile vedere che se si desidera avere a Mapcon Lists come valori, per avere k valori diversi, è necessario creare k elenchi diversi.
Pertanto: non è possibile evitare la creazione di questi elenchi, gli elenchi dovranno essere creati.

Possibile soluzione:
dichiarare il proprio Mapcome Map<String,Set>o Map<String,Collection>invece e inserire semplicemente il set.


1
mi dispiace era mainMap non elenco. vedi domanda
Muhammad Imran Tariq,

@imrantariq: sta differentKeyNamecambiando ogni iterazione? Vuoi davvero something.size()diversi valori possibili nelle tue mappe? È facile vedere che una mappa con kelenchi come valori deve creare almeno kelenchi.
Amit

@imrantariq: e vuoi un elenco diverso per ogni chiave che presumo?
Amit

@imrantariq: ciò che stai richiedendo è impossibile. leggi la mia modifica per maggiori dettagli.
Amit

Restituirà NullPointerException nel caso in cui set sia nullo.
w35l3y,

411

Usa il costruttore per convertirlo:

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

21
Ha detto specificamente che vuole evitare questo.
mapeters

3
@mook Irrilevante, poiché il suo requisito non è implementabile.
Marchese di Lorne,

16
@EJP quindi la sua risposta deve dire che, invece di dichiarare semplicemente qualcosa che l'OP non ha richiesto senza alcuna spiegazione.
mapeters

lo sta evitando, quel costruttore usa System.arrayCopy, che crea copie superficiali, il che significa che copia solo i riferimenti degli oggetti nella matrice utilizzata per creare l'elenco. Se confronti entrambe le raccolte, vedrai che entrambe contengono riferimenti agli stessi oggetti.
Gubatron,

Questo in realtà non funziona su Android. Qualche ragione per cui?
kbluue,

84

Inoltre dalla libreria Guava Collect, puoi usare newArrayList(Collection):

Lists.newArrayList([your_set])

Questo sarebbe molto simile alla precedente risposta di amit , tranne per il fatto che non è necessario dichiarare (o istanziare) alcun listoggetto.


1
Se stai usando guava, questo è utile
vsingh

6
Anche se non si chiama direttamente il costruttore, questo metodo chiama comunque il ArrayListcostruttore.
glen3b,

Se non dichiaro un Elenco, come posso utilizzare l'Elenco creato?
Koray Tugay,

@KorayTugay, bene estrai Lists.newArrayList ([your_set]) in una variabile (locale o globale). Ad esempio: Elenco <Foo> fooList = Lists.newArrayList (setOfFoo) Ma la tua domanda è difettosa. Se si crea un elenco, questo viene almeno implicitamente dichiarato (se non esplicitamente).
chaiyachaiya,

1
Qualche ipotesi sul perché questo abbia reso questo metodo? Non sembra niente di meglio di new ArrayList<>([your_set]).
DavidS,

49

Possiamo usare un solo liner in Java 8:

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

Ecco un piccolo esempio:

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
Per leggibilità non è raccomandato. Ad esempio, IntelliJ suggerisce "new ArrayList <> (set)" ed elenca più di 20 esempi di codice simili che possono essere sostituiti allo stesso modo.
rrhrg

Esattamente! @rrhrg che è meglio per le prestazioni se usiamo set.parallelStream ()?
gaurav,

31

la soluzione più semplice

Volevo un modo molto veloce per convertire il mio set in Elenco e restituirlo, quindi in una riga l'ho fatto

 return new ArrayList<Long>(mySetVariable);

1
Questo è anche ciò che IntelliJ IDEA suggerisce invece di API stream.
Ben

6

È possibile utilizzare questo cambio di una riga: 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()])));
}  

Dimensione corretta perché il nuovo oggetto [0] conterrà solo un elemento ma il nuovo oggetto [set.size ()] conterrà tutti i valori
rajadilipkolli

5

Farei :

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

Dal momento che non è stato menzionato finora, a partire da Java 10 è possibile utilizzare il nuovo copyOfmetodo factory:

List.copyOf(set);

Dal Javadoc :

Restituisce un Elenco non modificabile contenente gli elementi della Raccolta fornita, nel suo ordine di iterazione.


3

Java 8 offre la possibilità di utilizzare flussi e puoi ottenere un elenco da Set<String> setStringcome:

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

Sebbene l'implementazione interna al momento fornisca un'istanza di 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);
    }

ma JDK non lo garantisce. Come menzionato qui :

Non vi sono garanzie sul tipo, la mutabilità, la serializzabilità o la sicurezza dei thread dell'elenco restituito; se è necessario un maggiore controllo sull'Elenco reso, utilizzare toCollection (Fornitore).

Nel caso in cui si desideri essere sempre sicuri, è possibile richiedere un'istanza specificatamente come:

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

2

Creo un staticmetodo semplice :

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

... o se vuoi impostare il tipo di Elenco puoi usare:

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

Recentemente ho trovato questo:

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

1
Puoi espandere o approfondire di più su questo?
Vandal,

Collections.list () crea una nuova ArrayList: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

Per amor di completezza...

Supponiamo che tu voglia veramente trattare i Mapvalori come Lists, ma vuoi evitare di copiarli Setin Listogni volta.

Ad esempio, forse stai chiamando una funzione di libreria che crea una Set, ma stai passando il Map<String, List<String>>risultato a una funzione di libreria (mal progettata ma fuori dalle tue mani) che richiede solo Map<String, List<String>>, anche se in qualche modo sai che le operazioni che fa con Listsono ugualmente applicabili a qualsiasi Collection(e quindi a qualsiasi Set). E per qualche motivo è necessario evitare il sovraccarico di velocità / memoria della copia di ciascun set in un elenco.

In questo caso di super nicchia, a seconda del comportamento (forse inconoscibile) di cui la funzione di libreria necessita dai tuoi List, potresti essere in grado di creare una List vista su ogni set. Si noti che questo è intrinsecamente pericoloso (poiché i requisiti della funzione di libreria di ciascuno di essi Listpotrebbero presumibilmente cambiare a tua insaputa), quindi un'altra soluzione dovrebbe essere preferita. Ma ecco come lo faresti.

Dovresti creare una classe che implementa l' Listinterfaccia, prende un Setnel costruttore e assegna quel Set a un campo, e poi usi quello interno Setper implementare l' ListAPI (nella misura del possibile e desiderata).

Nota che alcuni comportamenti dell'elenco che semplicemente non sarai in grado di imitare senza memorizzare gli elementi come a List, e alcuni comportamenti che potrai imitare solo parzialmente. Ancora una volta, questa classe non è un rimpiazzo sicuro per Lists in generale. In particolare, se sai che il caso d'uso richiede operazioni relative all'indice o MUTAZIONI List, questo approccio andrebbe a sud molto velocemente.

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);
...

Questa è in realtà l'unica risposta che risolve effettivamente il problema dichiarato nella domanda!
Lii

Puoi implementarlo abbastanza facilmente estendendo AbstractList
Lii

1

Ho trovato questo funzionante e utile per creare un elenco da un set.

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
Non hai evitato di creare l'elenco. Questo codice è banalmente simile all'esempio nella tua domanda.
Taylor,

2
Ma non risponde al tuo quezon, non che ci sia una risposta.
Marchese di Lorne,
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.