ChatGPT解决这个技术问题 Extra ChatGPT

How to convert an Array to a Set in Java

I would like to convert an array to a Set in Java. There are some obvious ways of doing this (i.e. with a loop) but I would like something a bit neater, something like:

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

Any ideas?


J
Jackkobec

Like this:

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

In Java 9+, if unmodifiable set is ok:

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

In Java 10+, the generic type parameter can be inferred from the arrays component type:

var mySet = Set.of(someArray);

Be careful

Set.of throws IllegalArgumentException - if there are any duplicate elements in someArray. See more details: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Set.html#of(E...)


I would leave out the last , otherwise nice oneliner!
@dataoz: Wrong; Arrays.asList is O(1).
Note that if you use this method on an array of primitives such as int[] it will return a List so you should use wrapper classes to get the intended behavior.
@AjayGautam: That's only in Guava.
I'll take readability over efficiency (nearly) every time: blog.codinghorror.com/…
J
JavadocMD
Set<T> mySet = new HashSet<T>();
Collections.addAll(mySet, myArray);

That's Collections.addAll(java.util.Collection, T...) from JDK 6.

Additionally: what if our array is full of primitives?

For JDK < 8, I would just write the obvious for loop to do the wrap and add-to-set in one pass.

For JDK >= 8, an attractive option is something like:

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

You can do that with java.util.Collections.addAll. Plus, I wouldn't recommend Commons Collections anymore, what with it not being generified and Guava existing .
+1 for being more efficient than SLaks's answer, even though it's not a one-liner.
@Adrian I question that. I think addAll will be O(n).
I believe Adrian's point was about how SLaks' solution creates a List instance which is ultimately thrown out. The actual impact of that difference is probably extremely minimal, but could depend on the context in which you're doing this -- tight loops or very large sets might behave very differently between these two options.
Per the Collections.addAll() javadoc (Java 6): "The behavior of this convenience method is identical to that of c.addAll(Arrays.asList(elements)), but this method is likely to run significantly faster under most implementations."
C
ColinD

With Guava you can do:

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

also ImmutableSet.copyOf(array). (I like to point out also's, I guess.)
For a fixed list of elements you could use: ImmutableSet.of(e1, e2, ..., en). Notice you would not be able to change this Set after its creation.
Be warned, the Guava javadoc says: "This method is not actually very useful and will likely be deprecated in the future." They point towards the standard new HashSet<T>(Arrays.asList(someArray)). See google.github.io/guava/releases/19.0/api/docs/com/google/common/…
v
vega8

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]

Is it worth doing this in parallel?
@RaffiKhatchadourian This is not necessarily being done in parallel. Arrays.stream does not make any promises on the stream. You would have to call parallel() on the resulting stream for that.
You could also call parallelStream(). To answer @RaffiKhatchadourian's question, probably not. Try measuring if you're noticing any performance issues.
Generally, avoid parallel. By default it uses a single threadpool accross your application, and the overhead to start threads and join is worse than sequentially streaming through hundreds of items. Only in very few situations does parallel actually bring benefit.
A
Alex

Varargs will work too!

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

way better that 2-3 liners.
a
akhil_mittal

Java 8

We have the option of using Stream as well. We can get stream in various ways:

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

The source code of Collectors.toSet() shows that elements are added one by one to a HashSet but specification does not guarantee it will be a HashSet.

"There are no guarantees on the type, mutability, serializability, or thread-safety of the Set returned."

So it is better to use the later option. The output is: [A, B, C, D] [A, B, C, D] [A, B, C, D]

Immutable Set (Java 9)

Java 9 introduced Set.of static factory method which returns immutable set for the provided elements or the array.

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

Check Immutable Set Static Factory Methods for details.

Immutable Set (Java 10)

We can also get an immutable set in two ways:

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

The method Collectors.toUnmodifiableList() internally makes use of Set.of introduced in Java 9. Also check this answer of mine for more.


+1 for Stream.of() - I didn't know that one. A small quibble about Collectors.toSet(): you say the spec does not guarantee adding elements one by one, but that's what it means by: "accumulates ... into a new Set". And it's more readable - so preferable to my mind, if you don't need the guarantees of concrete type, mutability, serializability and thread-safety.
@AndrewSpencer Spec does not guarantee that the set implementation will be HashSet. It only guarantees that it will be a Set and that is what I mean. Hope I clarified it.
Sorry, and thanks, I misread it as meaning "spec does not guarantee added one by one" rather than "spec does not guarantee a HashSet". Proposed an edit to clarify.
P
Petar Minchev

After you do Arrays.asList(array) you can execute Set set = new HashSet(list);

Here is a sample method, you can write:

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

I was hoping for a method that returns a set directly from an array, does one exist?
You can write your own, if you are so eager:)
K
Kennard

There has been a lot of great answers already, but most of them won't work with array of primitives (like int[], long[], char[], byte[], etc.)

In Java 8 and above, you can box the array with:

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

Then convert to set using stream:

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

D
Donald Raab

In Eclipse Collections, the following will work:

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

Note: I am a committer for Eclipse Collections


P
Pierre-Olivier Pignon

Quickly : you can do :

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

and to reverse

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

A
Ashley Frieze

I've written the below from the advice above - steal it... it's nice!

/**
 * 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 may be better than Stream.of for the above.
S
Stypox

If you need to build an immutable set with only one element inside it, you can use Collections.singleton(...). Here is an example:

Set<String> mySet = Collections.singleton("Have a good day :-)");

This doesn't answer the original question but might be useful to someone (it would have been at least to me). If you think this answer does not fit just tell me and I will delete it.


m
mnagni

Sometime using some standard libraries helps a lot. Try to look at the Apache Commons Collections. In this case your problems is simply transformed to something like this

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

And here is the CollectionsUtils javadoc


user might not use apache commons
if the user does not use apache commons, then that is his first mistake.
why would you use this instead of java.util.Collections.addAll(myEmptySet, keys);??
O
Olexandra Dmytrenko

Use CollectionUtils or ArrayUtils from stanford-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);

O
Oleksandr Pyrohov

In Java 10:

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

Set.copyOf returns an unmodifiable Set containing the elements of the given Collection.

 The given Collection must not be null, and it must not contain any null elements.


M
Miss Chanandler Bong
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());

the output is

expected size is 3: 1

change it to

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

the output is

expected size is 3: 3

G
Gibolt

For anyone solving for Android:

Kotlin Collections Solution

The asterisk * is the spread operator. It applies all elements in a collection individually, each passed in order to a vararg method parameter. It is equivalent to:

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)

Passing no parameters setOf() results in an empty set.

In addition to setOf, you can also use any of these for a specific hash type:

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

This is how to define the collection item type explicitly.

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

Z
Zorb

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

But I think this would be more efficient:

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

That wouldn't really be more efficient (at least not worth thinking about).
With the constructor version, the initial capacity of the HashSet is set based on the size of the array, for instance.
this answer is not so dumb as it seems: 'Collections.addAll(mySet, myArray);' from java.util.Collections use the same iterator but plus one boolean operation . Plus as Bert F pointed out Collections.addAll " likely to run significantly faster under most implementations" than c.addAll(Arrays.asList(elements))
S
Slava Vedenin
Set<T> b = new HashSet<>(Arrays.asList(requiredArray));

In what aspect does you answer differ from the implementation @SLaks has provided as least 6 years ago? stackoverflow.com/a/3064447