Jak przekonwertować tablicę na zestaw w Javie

717

Chciałbym przekonwertować tablicę na zestaw w Javie. Istnieje kilka oczywistych sposobów na zrobienie tego (np. Za pomocą pętli), ale chciałbym coś bardziej schludnego, na przykład:

java.util.Arrays.asList(Object[] a);

Jakieś pomysły?

Bob Gilmore
źródło

Odpowiedzi:

1226

Lubię to:

Set<T> mySet = new HashSet<>(Arrays.asList(someArray));

W Javie 9+, jeśli niemodyfikowalny zestaw jest w porządku:

Set<T> mySet = Set.of(someArray);

W Javie 10+ parametr typu ogólnego można wywnioskować na podstawie typu komponentu tablic:

var mySet = Set.of(someArray);
SLaks
źródło
10
Opuściłbym ostatni <T>, w przeciwnym razie miły oneliner!
despot
165
@dataoz: Wrong; Arrays.asListoznacza O (1).
SLaks,
67
Zauważ, że jeśli użyjesz tej metody na tablicy prymitywów takich jak int [], zwróci ona List <int []>, więc powinieneś użyć klas opakowujących, aby uzyskać zamierzone zachowanie.
T. Markle,
6
@AjayGautam: To tylko w Guava.
SLaks,
10
Wezmę czytelność ponad wydajność (prawie) za każdym razem: blog.codinghorror.com/...
David Carboni
221
Set<T> mySet = new HashSet<T>();
Collections.addAll(mySet, myArray);

To jest Collection.addAll (java.util.Collection, T ...) z JDK 6.

Dodatkowo: co jeśli nasza tablica jest pełna prymitywów?

Dla JDK <8 po prostu napisałbym oczywistą forpętlę, aby wykonać zawijanie i dodawanie do zestawu w jednym przebiegu.

Dla JDK> = 8 atrakcyjną opcją jest coś takiego:

Arrays.stream(intArray).boxed().collect(Collectors.toSet());
JavadocMD
źródło
5
Możesz to zrobić za pomocą java.util.Collections.addAll. Poza tym nie polecałbym już kolekcji Commons, co nie jest generowane, a Guava istnieje.
ColinD
14
+1 za bycie bardziej wydajnym niż odpowiedź SLaksa, nawet jeśli nie jest to jedna linijka.
Adrian
1
@Adrian Mam to pytanie. Myślę, że addAllbędzie O ( n ).
Steve Powell,
1
Uważam, że punkt Adriana dotyczył sposobu, w jaki rozwiązanie SLaks tworzy instancję List, która jest ostatecznie wyrzucana. Rzeczywisty wpływ tej różnicy jest prawdopodobnie bardzo minimalny, ale może zależeć od kontekstu, w którym to robisz - ciasne pętle lub bardzo duże zestawy mogą zachowywać się bardzo różnie między tymi dwiema opcjami.
JavadocMD
13
Według kolekcji.addAll () javadoc (Java 6): „Zachowanie tej wygodnej metody jest identyczne jak w przypadku c.addAll (Arrays.asList (elements)), ale ta metoda prawdopodobnie będzie działać znacznie szybciej w większości implementacji. „
Bert F
124

Z Guava możesz:

T[] array = ...
Set<T> set = Sets.newHashSet(array);
ColinD
źródło
27
także ImmutableSet.copyOf (tablica). (Chyba lubię też wskazywać na).
Kevin Bourrillion,
Aby uzyskać stałą listę elementów, możesz użyć: ImmutableSet.of (e1, e2, ..., en). Zauważ, że nie będziesz mógł zmienić tego Zestawu po jego utworzeniu.
pisaruk,
1
Ostrzegam, javadoc z Guawy mówi: „Ta metoda nie jest tak naprawdę bardzo przydatna i prawdopodobnie zostanie wycofana w przyszłości”. Wskazują na standard new HashSet<T>(Arrays.asList(someArray)). Zobacz google.github.io/guava/releases/19.0/api/docs/com/google/common/…
Alexander Klimetschek
67

Java 8:

String[] strArray = {"eins", "zwei", "drei", "vier"};

Set<String> strSet = Arrays.stream(strArray).collect(Collectors.toSet());
System.out.println(strSet);
// [eins, vier, zwei, drei]
max
źródło
2
Czy warto to robić równolegle?
Raffi Khatchadourian
@RaffiKhatchadourian Niekoniecznie odbywa się to równolegle. Arrays.stream nie składa żadnych obietnic w strumieniu. W tym celu musiałbyś wywołać równoległy () strumień wynikowy.
Felix S
Możesz także wywołać parallelStream (). Aby odpowiedzieć na pytanie @ RaffiKhatchadourian, prawdopodobnie nie. Spróbuj zmierzyć, jeśli zauważysz jakiekolwiek problemy z wydajnością.
Randy the Dev
6
Ogólnie rzecz biorąc, unikaj równoległości. Domyślnie używa pojedynczej puli wątków w całej aplikacji, a narzut związany z uruchamianiem wątków i łączeniem jest gorszy niż sekwencyjne przesyłanie strumieniowe przez setki elementów. Tylko w bardzo niewielu sytuacjach równoległość faktycznie przynosi korzyści.
tkruse
45

Varargs też będzie działać!

Stream.of(T... values).collect(Collectors.toSet());
Alex
źródło
2
o wiele lepiej niż 2-3 wkładki.
senseiwu
30

Java 8

Mamy również opcję korzystania Stream. Możemy uzyskać strumień na różne sposoby:

Set<String> set = Stream.of("A", "B", "C", "D").collect(Collectors.toCollection(HashSet::new));
System.out.println(set);

String[] stringArray = {"A", "B", "C", "D"};
Set<String> strSet1 = Arrays.stream(stringArray).collect(Collectors.toSet());
System.out.println(strSet1);

// if you need HashSet then use below option.
Set<String> strSet2 = Arrays.stream(stringArray).collect(Collectors.toCollection(HashSet::new));
System.out.println(strSet2);

Kod źródłowy Collectors.toSet()pokazuje, że elementy są dodawane jeden po drugim, HashSetale specyfikacja nie gwarantuje, że będzie to HashSet.

„Nie ma żadnych gwarancji dotyczących rodzaju, zmienności, możliwości serializacji ani bezpieczeństwa wątków zwracanego zestawu”.

Lepiej więc użyć późniejszej opcji. Dane wyjściowe to: [A, B, C, D] [A, B, C, D] [A, B, C, D]

Niezmienny zestaw (Java 9)

Java 9 wprowadziła Set.ofstatyczną metodę fabryczną, która zwraca niezmienny zestaw dla dostarczonych elementów lub tablicy.

@SafeVarargs
static <E> Set<E> of​(E... elements)

Sprawdź szczegółowe informacje na temat niezmiennych metod statycznych .

Niezmienny zestaw (Java 10)

Możemy również uzyskać niezmienny zestaw na dwa sposoby:

  1. Set.copyOf(Arrays.asList(array))
  2. Arrays.stream(array).collect(Collectors.toUnmodifiableList());

Ta metoda Collectors.toUnmodifiableList()korzysta z metody wewnętrznej Set.ofwprowadzonej w Javie 9. Sprawdź także moją odpowiedź, aby uzyskać więcej.

akhil_mittal
źródło
1
+1 za Stream.of()- nie znałem tego. Mały spór o Collectors.toSet(): mówisz, że specyfikacja nie gwarantuje dodawania elementów jeden po drugim, ale to właśnie oznacza: „kumuluje się ... w nowy Set”. I jest bardziej czytelny - tak uważam, jeśli nie potrzebujesz gwarancji konkretnego typu, zmienności, możliwości serializacji i bezpieczeństwa wątków.
Andrew Spencer,
@AndrewSpencer Spec nie gwarantuje, że będzie to ustawiona implementacja HashSet. To tylko gwarantuje, że będzie to Seti właśnie o to mi chodzi. Mam nadzieję, że to wyjaśniłem.
akhil_mittal
Przepraszam i dziękuję, źle go odczytałem, co oznacza, że ​​„spec nie gwarantuje dodawania jeden po drugim” zamiast „spec nie gwarantuje HashSet”. Zaproponowano zmianę w celu wyjaśnienia.
Andrew Spencer
19

Po zakończeniu możesz Arrays.asList(array)wykonaćSet set = new HashSet(list);

Oto przykładowa metoda, którą możesz napisać:

public <T> Set<T> GetSetFromArray(T[] array) {
    return new HashSet<T>(Arrays.asList(array));
}
Petar Minchev
źródło
Miałem nadzieję na metodę, która zwraca zestaw bezpośrednio z tablicy, czy istnieje?
1
Możesz pisać własne, jeśli jesteś taki chętny :)
Petar Minchev
12

W kolekcji Eclipse działają następujące elementy:

Set<Integer> set1 = Sets.mutable.of(1, 2, 3, 4, 5);
Set<Integer> set2 = Sets.mutable.of(new Integer[]{1, 2, 3, 4, 5});
MutableSet<Integer> mutableSet = Sets.mutable.of(1, 2, 3, 4, 5);
ImmutableSet<Integer> immutableSet = Sets.immutable.of(1, 2, 3, 4, 5);

Set<Integer> unmodifiableSet = Sets.mutable.of(1, 2, 3, 4, 5).asUnmodifiable();
Set<Integer> synchronizedSet = Sets.mutable.of(1, 2, 3, 4, 5).asSynchronized();
ImmutableSet<Integer> immutableSet = Sets.mutable.of(1, 2, 3, 4, 5).toImmutable();

Uwaga: jestem osobą odpowiedzialną za kolekcje Eclipse

Donald Raab
źródło
7

Szybko: możesz:

// Fixed-size list
List list = Arrays.asList(array);

// Growable list
list = new LinkedList(Arrays.asList(array));

// Duplicate elements are discarded
Set set = new HashSet(Arrays.asList(array));

i odwrócić

// Create an array containing the elements in a list
Object[] objectArray = list.toArray();
MyClass[] array = (MyClass[])list.toArray(new MyClass[list.size()]);

// Create an array containing the elements in a set
objectArray = set.toArray();
array = (MyClass[])set.toArray(new MyClass[set.size()]);
Pierre-Olivier Pignon
źródło
6

Napisałem poniżej z powyższej porady - ukraść to ... to miłe!

/**
 * Handy conversion to set
 */
public class SetUtil {
    /**
     * Convert some items to a set
     * @param items items
     * @param <T> works on any type
     * @return a hash set of the input items
     */
    public static <T> Set<T> asSet(T ... items) {
        return Stream.of(items).collect(Collectors.toSet());
    }
}
Ashley Frieze
źródło
Arrays.stream może być lepszy niż Stream.of dla powyższego.
Ashley Frieze,
5

Odnotowano wiele wspaniałych odpowiedzi już, ale większość z nich nie będzie działać z tablicy prymitywów (jak int[], long[], char[], byte[], itd.)

W Javie 8 i nowszych możesz umieścić tablicę w pudełku za pomocą:

Integer[] boxedArr = Arrays.stream(arr).boxed().toArray(Integer[]::new);

Następnie przekonwertuj na zestaw za pomocą strumienia:

Stream.of(boxedArr).collect(Collectors.toSet());
Julia
źródło
0

Kiedyś korzystanie ze standardowych bibliotek bardzo pomaga. Spróbuj spojrzeć na Kolekcje Apache Commons . W takim przypadku Twoje problemy są po prostu przekształcane w coś takiego

String[] keys = {"blah", "blahblah"}
Set<String> myEmptySet = new HashSet<String>();
CollectionUtils.addAll(pythonKeywordSet, keys);

A oto javadoc CollectionsUtils

mnagni
źródło
4
użytkownik nie może korzystać z apache commons
Adrian
jeśli użytkownik nie używa wspólnych apache, to jest to jego pierwszy błąd.
Jeryl Cook
3
dlaczego miałbyś użyć tego zamiast java.util.Collections.addAll(myEmptySet, keys);??
djeikyb
0

Użyj CollectionUtilslub ArrayUtilszstanford-postagger-3.0.jar

import static edu.stanford.nlp.util.ArrayUtils.asSet;
or 
import static edu.stanford.nlp.util.CollectionUtils.asSet;

  ...
String [] array = {"1", "q"};
Set<String> trackIds = asSet(array);
Oleksandra Dmytrenko
źródło
0

W Javie 10 :

String[] strs = {"A", "B"};
Set<String> set = Set.copyOf(Arrays.asList(strs));

Set.copyOfzwraca niemodyfikowalną Setzawierającą elementy danego Collection.

 Podane Collectionnie może być nulli nie może zawierać żadnych nullelementów.

Oleksandr Pyrohov
źródło
0
private Map<Integer, Set<Integer>> nobreaks = new HashMap();
nobreaks.put(1, new HashSet(Arrays.asList(new int[]{2, 4, 5})));
System.out.println("expected size is 3: " +nobreaks.get(1).size());

wyjście jest

expected size is 3: 1

zmień na

nobreaks.put(1, new HashSet(Arrays.asList( 2, 4, 5 )));

wyjście jest

expected size is 3: 3
Bruce Zu
źródło
-1

Dla każdego, kto rozwiązuje problem dla Androida:

Rozwiązanie Kotlin Collections

Gwiazdką *jest spreadoperator. Stosuje wszystkie elementy w kolekcji osobno, każdy przekazany w celu varargparametru metody. Jest to równoważne z:

val myArray = arrayOf("data", "foo")
val mySet = setOf(*myArray)

// Equivalent to
val mySet = setOf("data", "foo")

// Multiple spreads ["data", "foo", "bar", "data", "foo"]
val mySet = setOf(*myArray, "bar", *myArray)

Nieprzekazanie parametrów setOf()powoduje powstanie pustego zestawu.

Oprócz tego setOfmożesz użyć dowolnego z nich dla określonego typu skrótu:

hashSetOf()
linkedSetOf()
mutableSetOf()
sortableSetOf()

W ten sposób można jawnie zdefiniować typ elementu kolekcji.

setOf<String>()
hashSetOf<MyClass>()
Gibolt
źródło
-2

new HashSet<Object>(Arrays.asList(Object[] a));

Ale myślę, że byłoby to bardziej wydajne:

final Set s = new HashSet<Object>();    
for (Object o : a) { s.add(o); }         
Ben S.
źródło
To naprawdę nie byłoby bardziej wydajne (przynajmniej nie warto o tym myśleć).
ColinD
3
W wersji konstruktora początkowa pojemność HashSetzestawu jest ustalana na przykład na podstawie rozmiaru tablicy.
ColinD
3
ta odpowiedź nie jest tak głupia, jak się wydaje: „Collections.addAll (mySet, myArray);” z java.util.Collections używają tego samego iteratora, ale plus jedna operacja boolowska. Plus, jak zauważył Bert F., Collection.addAll „prawdopodobnie będzie działał znacznie szybciej w większości implementacji” niż c.addAll (Arrays.asList (elements))
Zorb
-4
Set<T> b = new HashSet<>(Arrays.asList(requiredArray));
Satyendra Jaiswal
źródło
1
W jakim aspekcie odpowiedź różni się od wdrożenia zapewnionego przez @SLaks co najmniej 6 lat temu? stackoverflow.com/a/3064447
Ferrybig