Konwertuj Ustaw na listę bez tworzenia nowej listy


503

Używam tego kodu do konwersji Setna 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);
}

Chcę uniknąć tworzenia nowej listy w każdej iteracji pętli. Czy to jest możliwe?


1
Znam sposób na konwersję zestawu do listy jak w Q. Chcę uniknąć tworzenia nowej listy za każdym razem w pętli.
Muhammad Imran Tariq

4
Dlaczego nie możesz po prostu dodać zestawu do listy głównej? Dlaczego musisz przekonwertować zestaw na listę?
DagR

1
Czy masz zamiar utworzyć List <List <? >>
Hiery Nomus

5
Nie możesz Twoje pytanie ucieleśnia sprzeczność.
Markiz Lorne

Odpowiedzi:


802

Możesz użyć metody List.addAll () . Akceptuje kolekcję jako argument, a twój zestaw jest kolekcją.

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

EDYCJA: w odpowiedzi na edycję pytania.
Łatwo jest zauważyć, że jeśli chcesz mieć Mapze Lists jako wartości, aby mieć różne wartości k, trzeba utworzyć k różnych list.
Zatem: Nie można w ogóle uniknąć tworzenia tych list, listy będą musiały zostać utworzone.

Możliwe obejście:
zadeklaruj Mapjako Map<String,Set>lub Map<String,Collection>zamiast, i po prostu wstaw swój zestaw.


1
przepraszam, że to mainMap nie ma listy. patrz pytanie
Muhammad Imran Tariq

@imrantariq: czy differentKeyNamezmienia się każda iteracja? Czy faktycznie chcesz something.size()różnych możliwych wartości na swoich mapach? Łatwo zauważyć, że mapa z klistami jako wartościami musi tworzyć przynajmniej klisty.
amit

@imrantariq: a chcesz inną listę dla każdego klucza, który zakładam?
dniu

@imrantariq: To, o co prosisz, jest niemożliwe. przeczytaj moją edycję, aby uzyskać więcej informacji.
amit

Zwróci NullPointerException, jeśli zestaw ma wartość NULL.
w35l3y 30.08.16

411

Użyj konstruktora, aby go przekonwertować:

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

21
W szczególności powiedział, że chce tego uniknąć.
twórcy map

3
@mook Nieistotne, ponieważ jego wymaganie nie jest możliwe do wdrożenia.
Markiz Lorne

16
@EJP, więc jego odpowiedź musi powiedzieć, że zamiast po prostu podać coś, o co OP nie prosiło bez żadnego wyjaśnienia.
mapery

unika tego, że konstruktor używa System.arrayCopy, który tworzy płytkie kopie, co oznacza, że ​​kopiuje tylko referencje obiektów do tablicy używanej do tworzenia listy. Jeśli porównasz obie kolekcje, zobaczysz, że obie zawierają odniesienia do tych samych obiektów.
Gubatron

To nie działa na Androidzie. Jakiś powód dlaczego?
kbluue

84

Również z biblioteki Guava Collect możesz użyć newArrayList(Collection):

Lists.newArrayList([your_set])

Byłoby to bardzo podobne do poprzedniej odpowiedzi z amit , z tym wyjątkiem, że nie musisz deklarować (ani instynktować) żadnego listobiektu.


1
Jeśli używasz guawy, jest to przydatne
vsingh

6
Chociaż nie wywołujesz bezpośrednio konstruktora, ta metoda nadal wywołuje ArrayListkonstruktor.
glen3b

Jeśli nie zadeklaruję listy, jak mogę korzystać z utworzonej listy?
Koray Tugay

@ KorayTugay, dobrze wyodrębnij Lists.newArrayList ([twój_ zestaw]) w zmiennej (lokalnej lub globalnej). Np .: List <Foo> fooList = Lists.newArrayList (setOfFoo) Ale twoje pytanie jest błędne. Jeśli utworzysz listę, zostanie ona przynajmniej niejawnie zadeklarowana (jeśli nie jawnie).
chaiyachaiya

1
Zgadłeś, dlaczego to ta metoda? Nie wydaje się lepszy niż new ArrayList<>([your_set]).
DavidS

49

W Javie 8 możemy użyć jednego linera:

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

Oto jeden mały przykład:

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
Ze względu na czytelność nie jest zalecane. Na przykład IntelliJ sugeruje „nowy ArrayList <> (zestaw)” i wyświetla listę ponad 20 podobnych próbek kodu, które można zastąpić w ten sam sposób.
rrhrg

dokładnie! @rrhrg, który jest lepszy dla wydajności, jeśli użyjemy set.parallelStream ()?
gaurav

31

najprostsze rozwiązanie

Chciałem bardzo szybko przekonwertować mój zestaw na List i zwrócić go, więc zrobiłem to w jednym wierszu

 return new ArrayList<Long>(mySetVariable);

1
To również sugeruje IntelliJ IDEA zamiast interfejsu API strumieni.
Ben

6

Możesz użyć tej zmiany jednej linii: 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()])));
}  

Poprawiono rozmiar, ponieważ nowy obiekt [0] będzie zawierał tylko jeden element, ale nowy obiekt [set.size ()] będzie przechowywać wszystkie wartości
rajadilipkolli

5

Chciałbym zrobić :

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

Ponieważ nie wspomniano do tej pory, od wersji Java 10 można korzystać z nowej copyOfmetody fabrycznej:

List.copyOf(set);

Z Javadoc :

Zwraca niemodyfikowalną listę zawierającą elementy danej kolekcji w kolejności iteracji.


3

Java 8 zapewnia opcję korzystania ze strumieni i możesz uzyskać listę z Set<String> setString:

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

Chociaż wewnętrzna implementacja zapewnia obecnie wystąpienie 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);
    }

ale JDK tego nie gwarantuje. Jak wspomniano tutaj :

Nie ma gwarancji na rodzaj, zmienność, serializację lub bezpieczeństwo wątków zwracanej listy; jeśli wymagana jest większa kontrola nad zwracaną listą, użyj funkcji toCollection (dostawca).

Jeśli chcesz być zawsze pewien, możesz poprosić o wystąpienie, w szczególności jako:

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

2

Tworzę prostą staticmetodę:

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

... lub jeśli chcesz ustawić typ listy, możesz użyć:

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

Ostatnio znalazłem to:

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

1
Czy możesz rozwinąć lub rozwinąć więcej na ten temat?
Wandal

Collections.list () tworzy nową 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

Ze względu na kompletność ...

Powiedz, że naprawdę chcesz traktować Mapwartości jako Lists, ale chcesz uniknąć kopiowania Setdo za Listkażdym razem.

Na przykład, może wywołujesz jedną funkcję biblioteczną, która tworzy Set, ale przekazujesz swój Map<String, List<String>>wynik do (słabo zaprojektowanej, ale wymykającej się z ręki) funkcji bibliotecznej, która bierze tylko Map<String, List<String>>, chociaż jakoś wiesz, że operacje, które wykonuje z Lists mają jednakowe zastosowanie do dowolnych Collection(a zatem dowolnych Set). I z jakiegoś powodu musisz unikać narzutu / pamięci związanego z kopiowaniem każdego zestawu do listy.

W tym bardzo niszowym przypadku, w zależności od (być może niepoznawalnego) zachowania funkcji biblioteki Listwymaganej od ciebie , możesz być w stanie stworzyć List widok każdego zestawu. Zauważ, że jest to z natury niebezpieczne (ponieważ wymagania funkcji bibliotecznych dla każdej z nich Listmogą prawdopodobnie ulec zmianie bez twojej wiedzy), dlatego należy preferować inne rozwiązanie. Ale oto jak to zrobisz.

Utworzyłbyś klasę, która implementuje Listinterfejs, bierze Setkonstruktora i przypisuje ten zestaw do pola, a następnie używa tego wewnętrznego Setdo implementacji Listinterfejsu API (w możliwym zakresie i pożądanym).

Zwróć uwagę, że niektóre zachowania List po prostu nie będą w stanie naśladować bez przechowywania elementów jako a List, a niektóre zachowania będą tylko częściowo możliwe do naśladowania. Ponownie, ta klasa nie jest Listogólnie bezpiecznym zamiennikiem dla s. W szczególności, jeśli wiesz, że przypadek użycia wymaga operacji związanych z indeksem lub MUTOWANIA List, to podejście pójdzie bardzo szybko na południe.

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

To właściwie jedyna odpowiedź, która faktycznie rozwiązuje zadany problem w pytaniu!
Lii

Możesz to dość łatwo wdrożyć, rozszerzając AbstractList
Lii

1

Uważam, że to działa dobrze i przydatne do tworzenia listy z zestawu.

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
Nie unikałeś tworzenia listy. Ten kod jest trywialnie podobny do próbki w twoim pytaniu.
Taylor,

2
Ale to nie odpowiada na twój quezon, nie że nie ma odpowiedzi.
Markiz Lorne
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.