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?

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

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

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

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]

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

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.


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

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


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()]);

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());
    }
}

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

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


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

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.


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

-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>()

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

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

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.