Set in Liste konvertieren, ohne eine neue Liste zu erstellen


503

Ich benutze diesen Code, um a Setin a umzuwandeln 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);
}

Ich möchte vermeiden, in jeder Iteration der Schleife eine neue Liste zu erstellen. Ist das möglich?


1
Ich kenne eine Möglichkeit, set in list wie in Q zu konvertieren. Ich möchte vermeiden, jedes Mal in einer Schleife eine neue Liste zu erstellen.
Muhammad Imran Tariq

4
Warum können Sie das Set nicht einfach zur mainList hinzufügen? Warum müssen Sie das Set in eine Liste konvertieren?
DagR

1
Ist es Ihre Absicht, eine Liste <Liste <zu erstellen? >>
Hiery Nomus

5
Das kannst du nicht. Ihre Frage verkörpert einen Widerspruch.
Marquis von Lorne

Antworten:


802

Sie können die List.addAll () -Methode verwenden. Es akzeptiert eine Sammlung als Argument, und Ihr Satz ist eine Sammlung.

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

BEARBEITEN: als Antwort auf die Bearbeitung der Frage.
Es ist leicht zu erkennen, dass Sie k verschiedene Listen erstellen müssen , wenn Sie a Mapmit Lists als Werte haben möchten , um k verschiedene Werte zu haben.
Also: Sie können das Erstellen dieser Listen überhaupt nicht vermeiden, die Listen müssen erstellt werden.

Mögliche
Umgehung : Deklarieren Sie Ihre Mapals Map<String,Set>oder oder Map<String,Collection>fügen Sie einfach Ihr Set ein.


1
Entschuldigung, es war mainMap nicht Liste. siehe Frage
Muhammad Imran Tariq

@imrantariq: differentKeyNameändert sich jede Iteration? Möchten Sie tatsächlich something.size()verschiedene mögliche Werte in Ihren Karten? Es ist leicht zu erkennen, dass eine Karte mit kListen als Werten mindestens kListen erstellen muss .
Amit

@imrantariq: und du willst eine andere Liste für jeden Schlüssel, den ich annehme?
Amit

@imrantariq: Was Sie anfordern, ist unmöglich. Lesen Sie meine Bearbeitung für weitere Details.
Amit

Es wird NullPointerException zurückgegeben, falls set null ist.
w35l3y

411

Verwenden Sie den Konstruktor, um es zu konvertieren:

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

21
Er sagte ausdrücklich, er wolle dies vermeiden.
Mapeters

3
@mook Irrelevant, da seine Anforderung nicht umsetzbar ist.
Marquis von Lorne

16
@EJP dann muss seine Antwort sagen, dass, anstatt einfach etwas zu sagen, das das OP nicht ohne Erklärung verlangt hat.
Mapeters

Er vermeidet es, dass der Konstruktor System.arrayCopy verwendet, das flache Kopien erstellt, dh, er kopiert nur die Referenzen der Objekte in das Array, das zum Erstellen der Liste verwendet wird. Wenn Sie beide Sammlungen vergleichen, werden Sie feststellen, dass beide Verweise auf dieselben Objekte enthalten.
Gubatron

Dies funktioniert unter Android nicht wirklich. Irgendein Grund warum?
kbluue

84

Auch aus der Guava Collect-Bibliothek können Sie Folgendes verwenden newArrayList(Collection):

Lists.newArrayList([your_set])

Dies wäre der vorherigen Antwort von amit sehr ähnlich , außer dass Sie kein listObjekt deklarieren (oder instanziieren) müssen .


1
Wenn Sie Guave verwenden, ist dies praktisch
vsingh

6
Obwohl Sie den Konstruktor nicht direkt aufrufen, ruft diese Methode den ArrayListKonstruktor dennoch auf .
Glen3b

Wie kann ich die erstellte Liste verwenden, wenn ich keine Liste deklariere?
Koray Tugay

@KorayTugay, nun, Sie extrahieren Lists.newArrayList ([your_set]) in einer Variablen (lokal oder global). Beispiel: List <Foo> fooList = Lists.newArrayList (setOfFoo) Aber Ihre Frage ist fehlerhaft. Wenn Sie eine Liste erstellen, wird diese zumindest implizit deklariert (wenn nicht explizit).
Chaiyachaiya

1
Irgendwelche Vermutungen, warum dies diese Methode gemacht hat? Es scheint nicht besser als new ArrayList<>([your_set]).
DavidS

49

In Java 8 können wir folgenden Liner verwenden:

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

Hier ist ein kleines Beispiel:

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
Aus Gründen der Lesbarkeit wird dies nicht empfohlen. Zum Beispiel schlägt IntelliJ "new ArrayList <> (set)" vor und listet mehr als 20 ähnliche Codebeispiele auf, die auf die gleiche Weise ersetzt werden können.
rrhrg

genau! @rrhrg was ist besser für die Leistung, wenn wir set.parallelStream () verwenden?
Gaurav

31

die einfachste Lösung

Ich wollte einen sehr schnellen Weg, um mein Set in List umzuwandeln und zurückzugeben, also tat ich es in einer Zeile

 return new ArrayList<Long>(mySetVariable);

1
Dies ist auch das, was IntelliJ IDEA anstelle der Streams-API vorschlägt.
Ben

6

Sie könnten diese einzeilige Änderung verwenden: 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()])));
}  

Die Größe wurde korrigiert, da das neue Objekt [0] nur ein Element enthält, das neue Objekt [set.size ()] jedoch alle Werte enthält
rajadilipkolli

5

Ich würde tun:

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

Da dies bisher noch nicht erwähnt wurde, können Sie ab Java 10 die neue copyOfFactory-Methode verwenden:

List.copyOf(set);

Aus dem Javadoc :

Gibt eine nicht änderbare Liste zurück, die die Elemente der angegebenen Sammlung in ihrer Iterationsreihenfolge enthält.


3

Java 8 bietet die Möglichkeit, Streams zu verwenden, und Sie können eine Liste erhalten von Set<String> setString:

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

Die interne Implementierung bietet jedoch ab sofort eine Instanz von 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);
    }

JDK garantiert dies jedoch nicht. Wie hier erwähnt :

Es gibt keine Garantie für den Typ, die Veränderlichkeit, die Serialisierbarkeit oder die Thread-Sicherheit der zurückgegebenen Liste. Wenn mehr Kontrolle über die zurückgegebene Liste erforderlich ist, verwenden Sie toCollection (Lieferant).

Wenn Sie immer sicher sein möchten, können Sie eine Instanz speziell anfordern als:

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

2

Ich erstelle eine einfache staticMethode:

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

... oder wenn Sie den Listentyp festlegen möchten, können Sie Folgendes verwenden:

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

Kürzlich habe ich folgendes gefunden:

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

1
Können Sie dies näher erläutern oder näher erläutern?
Vandal

Collections.list () erstellt eine neue 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

Der Vollständigkeit halber...

Angenommen, Sie möchten die Werte wirklichMap als Lists behandeln, aber Sie möchten vermeiden, sie jedes Mal Setin ein zu kopieren List.

Zum Beispiel rufen Sie vielleicht eine Bibliotheksfunktion auf, die eine erstellt Set, aber Sie übergeben Ihr Map<String, List<String>>Ergebnis an eine (schlecht gestaltete, aber nicht in Ihren Händen befindliche) Bibliotheksfunktion, die nur benötigt wird Map<String, List<String>>, obwohl Sie irgendwie wissen, dass die Operationen, die sie mit der ausführt Lists gelten gleichermaßen für alle Collection(und damit alle Set). Und aus irgendeinem Grund Sie den Geschwindigkeits- / Speicheraufwand beim Kopieren jedes Sets in eine Liste vermeiden.

In diesem Super-Nischen-Fall können Sie abhängig vom (möglicherweise nicht erkennbaren) Verhalten, das die Bibliotheksfunktion von Ihrem Lists benötigt, möglicherweise eine List Ansicht über jedes Set erstellen . Beachten Sie, dass dies von Natur aus unsicher ist (da sich die Anforderungen der Bibliotheksfunktion Listvermutlich ändern können, ohne dass Sie es wissen). Daher sollte eine andere Lösung bevorzugt werden. Aber so würden Sie es machen.

Sie würden eine Klasse erstellen, die die ListSchnittstelle implementiert , ein Setim Konstruktor übernimmt und dieses Set einem Feld zuweist und dieses interne dann verwendet, Setum die ListAPI zu implementieren (soweit möglich und gewünscht).

Beachten Sie, dass einige Listenverhaltensweisen Sie einfach nicht imitieren können, ohne die Elemente als zu speichern List, und einige Verhaltensweisen, die Sie nur teilweise imitieren können. Auch diese Klasse ist Listim Allgemeinen kein sicherer Ersatz für s. Insbesondere wenn Sie wissen, dass der Anwendungsfall indexbezogene Operationen oder MUTATING the erfordert List, würde dieser Ansatz sehr schnell nach Süden gehen.

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

Dies ist tatsächlich die einzige Antwort, die das in der Frage angegebene Problem tatsächlich löst!
Lii

Sie können dies ziemlich einfach implementieren, indem Sie AbstractList
Lii

1

Ich fand das gut und nützlich, um eine Liste aus einem Set zu erstellen.

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
Sie haben es nicht vermieden, die Liste zu erstellen. Dieser Code ähnelt trivial dem Beispiel in Ihrer Frage.
Taylor

2
Aber es antwortet nicht auf Ihre Frage, nicht dass es eine Antwort gibt.
Marquis von Lorne
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.