Come convertire un array in un set in Java


717

Vorrei convertire un array in un set in Java. Ci sono alcuni modi ovvi per farlo (cioè con un ciclo) ma vorrei qualcosa di un po 'più ordinato, qualcosa del tipo:

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

Qualche idea?

Risposte:


1227

Come questo:

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

In Java 9+, se il set non modificabile è ok:

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

In Java 10+, il parametro di tipo generico può essere dedotto dal tipo di componente array:

var mySet = Set.of(someArray);

10
Tralascerei l'ultimo <T>, altrimenti bello oneliner!
despota il

165
@dataoz: Wrong; Arrays.asListè O (1).
SLaks

67
Si noti che se si utilizza questo metodo su una matrice di primitive come int [], verrà restituito un elenco <int []>, pertanto è necessario utilizzare le classi wrapper per ottenere il comportamento previsto.
T. Markle,

6
@AjayGautam: è solo in Guava.
SLaks

10
Prenderò la leggibilità sull'efficienza (quasi) ogni volta: blog.codinghorror.com/…
David Carboni

221
Set<T> mySet = new HashSet<T>();
Collections.addAll(mySet, myArray);

Quello è Collections.addAll (java.util.Collection, T ...) da JDK 6.

Inoltre: cosa succede se il nostro array è pieno di primitivi?

Per JDK <8, scriverei semplicemente il forciclo ovvio per eseguire il wrapping e aggiungere il set in un passaggio.

Per JDK> = 8, un'opzione interessante è qualcosa di simile:

Arrays.stream(intArray).boxed().collect(Collectors.toSet());

5
Puoi farlo con java.util.Collections.addAll. Inoltre, non consiglierei più le Collezioni Commons, cosa che non viene generata e che Guava esiste.
ColinD,

14
+1 per essere più efficiente della risposta di SLaks, anche se non è un one-liner.
Adrian,

1
@Adrian lo metto in dubbio. Penso che addAllsarà O ( n ).
Steve Powell,

1
Credo che il punto di Adrian riguardasse il modo in cui la soluzione di SLaks crea un'istanza di List che viene infine eliminata. L'impatto effettivo di tale differenza è probabilmente estremamente minimo, ma potrebbe dipendere dal contesto in cui lo stai facendo: loop ravvicinati o set molto grandi potrebbero comportarsi in modo molto diverso tra queste due opzioni.
JavadocMD,

13
Secondo il javadoc di Collections.addAll () (Java 6): "Il comportamento di questo metodo di convenienza è identico a quello di c.addAll (Arrays.asList (elements)), ma è probabile che questo metodo funzioni molto più rapidamente nella maggior parte delle implementazioni. "
Bert F

124

Con Guava puoi fare:

T[] array = ...
Set<T> set = Sets.newHashSet(array);

27
anche ImmutableSet.copyOf (array). (Mi piace sottolineare anche quello, immagino.)
Kevin Bourrillion,

Per un elenco fisso di elementi è possibile utilizzare: ImmutableSet.of (e1, e2, ..., en). Si noti che non sarà possibile modificare questo set dopo la sua creazione.
pisaruk,

1
Attenzione, il java di Guava dice: "Questo metodo non è in realtà molto utile e probabilmente sarà deprecato in futuro". Indicano lo standard new HashSet<T>(Arrays.asList(someArray)). Vedi 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
Vale la pena farlo in parallelo?
Raffi Khatchadourian,

@RaffiKhatchadourian Questo non è necessariamente fatto in parallelo. Arrays.stream non fa promesse sullo stream. Per questo dovresti chiamare parallel () sul flusso risultante.
Felix S,

Puoi anche chiamare parallelStream (). Per rispondere alla domanda di RaffiKhatchadourian, probabilmente no. Prova a misurare se noti problemi di prestazioni.
Randy the Dev,

6
In generale, evitare il parallelo. Per impostazione predefinita, utilizza un singolo threadpool nell'applicazione e l'overhead per avviare thread e join è peggiore rispetto allo streaming sequenziale di centinaia di elementi. Solo in pochissime situazioni il parallelo porta effettivamente benefici.
tkruse

45

Anche Varargs funzionerà!

Stream.of(T... values).collect(Collectors.toSet());

2
molto meglio di 2-3 fodere.
senseiwu,

30

Java 8

Abbiamo anche la possibilità di utilizzare Stream. Possiamo ottenere lo streaming in vari modi:

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

Il codice sorgente Collectors.toSet()mostra che gli elementi vengono aggiunti uno alla volta a un HashSetma la specifica non garantisce che sarà un HashSet.

"Non ci sono garanzie sul tipo, la mutabilità, la serializzabilità o la sicurezza del thread del set restituito."

Quindi è meglio usare l'opzione successiva. L'output è: [A, B, C, D] [A, B, C, D] [A, B, C, D]

Set immutabile (Java 9)

Java 9 introdotto Set.of metodo factory statico che restituisce un set immutabile per gli elementi forniti o l'array.

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

Controllare i metodi di fabbrica statici impostati immutabili per i dettagli.

Set immutabile (Java 10)

Possiamo anche ottenere un set immutabile in due modi:

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

Il metodo Collectors.toUnmodifiableList()utilizza internamente Set.ofintrodotto in Java 9. Controlla anche questa mia risposta per ulteriori informazioni.


1
+1 per Stream.of()- Non lo sapevo. Un piccolo cavillo su Collectors.toSet(): dici che la specifica non garantisce l'aggiunta di elementi uno per uno, ma è questo che significa: "accumula ... in un nuovo Set". Ed è più leggibile, quindi preferibile a me, se non hai bisogno delle garanzie di tipo concreto, mutabilità, serializzazione e sicurezza dei thread.
Andrew Spencer,

Le specifiche di @AndrewSpencer non garantiscono l'implementazione impostata HashSet. Garantisce solo che sarà un Sete questo è ciò che intendo. Spero di averlo chiarito.
akhil_mittal,

Siamo spiacenti, e grazie, ho letto male come "specifica non garantisce l'aggiunta uno per uno" anziché "specifica non garantisce un HashSet". Ha proposto una modifica per chiarire.
Andrew Spencer,

19

Dopo averlo fatto Arrays.asList(array)puoi eseguireSet set = new HashSet(list);

Ecco un metodo di esempio, puoi scrivere:

public <T> Set<T> GetSetFromArray(T[] array) {
    return new HashSet<T>(Arrays.asList(array));
}

Speravo in un metodo che restituisse un set direttamente da un array, ne esiste uno?

1
Puoi scriverne uno tuo, se sei così desideroso :)
Petar Minchev,

12

Nelle raccolte Eclipse , funzionerà quanto segue:

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

Nota: sono un committer per le raccolte Eclipse


7

Rapidamente: puoi fare:

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

e per invertire

// 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

Ho scritto quanto segue dai consigli sopra - rubalo ... è bello!

/**
 * 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 potrebbe essere migliore di Stream.of per quanto sopra.
Ashley Frieze,

5

C'è stato un sacco di grandi risposte già, ma la maggior parte di essi non funziona con array di primitive (come int[], long[], char[],byte[] , etc.)

In Java 8 e versioni successive, è possibile eseguire il box dell'array con:

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

Quindi converti in set usando stream:

Stream.of(boxedArr).collect(Collectors.toSet());

0

A volte l'utilizzo di alcune librerie standard aiuta molto. Prova a guardare le collezioni Apache Commons . In questo caso i tuoi problemi si trasformano semplicemente in qualcosa del genere

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

Ed ecco le CollezioniUtils javadoc


4
l'utente potrebbe non utilizzare apache commons
Adrian

se l'utente non usa i comuni di Apache, questo è il suo primo errore.
Jeryl Cook,

3
perché dovresti usare questo invece di java.util.Collections.addAll(myEmptySet, keys);??
djeikyb,

0

Usa CollectionUtilso ArrayUtilsdastanford-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

In Java 10 :

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

Set.copyOfrestituisce un non modificabile Setcontenente gli elementi del dato Collection.

 Il dato Collectionnon deve essere nulle non deve contenere alcun nullelemento.


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

l'uscita è

expected size is 3: 1

cambiarlo in

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

l'uscita è

expected size is 3: 3

-1

Per chiunque risolva per Android:

Kotlin Collections Solution

L'asterisco *è l' spreadoperatore. Applica tutti gli elementi in una raccolta singolarmente, ciascuno passato in ordine a un varargparametro di metodo. È equivalente a:

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)

Passando senza parametri si setOf()ottiene un set vuoto.

Inoltre setOf, puoi anche utilizzare uno di questi per un tipo di hash specifico:

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

Ecco come definire esplicitamente il tipo di elemento di raccolta.

setOf<String>()
hashSetOf<MyClass>()

-2

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

Ma penso che questo sarebbe più efficiente:

final Set s = new HashSet<Object>();    
for (Object o : a) { s.add(o); }         

Non sarebbe davvero più efficiente (almeno non vale la pena pensarci).
ColinD,

3
Con la versione del costruttore, la capacità iniziale di HashSetviene impostata in base alla dimensione dell'array, ad esempio.
ColinD,

3
questa risposta non è così stupida come sembra: 'Collections.addAll (mySet, myArray);' da java.util.Collections utilizza lo stesso iteratore ma più un'operazione booleana. Plus come Bert F sottolineato Collections.addAll "rischia di correre molto più velocemente nella maggior parte delle implementazioni" rispetto c.addAll (Arrays.asList (elementi))
Zorb

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.