How to merge multiple (arbitrary number of) Set<String> into one in Java?

collections, guava, java

Solution

In your previous attempt, you had written

Set<String> set = Utils.immutableSetOf(new Set<String>[] { One.SET, Two.SET });

This does not work because, generics array creation is not allowed in java

Try this:

@SuppressWarnings("unchecked")
Set<String>[] mySet = new Set[] { One.SET, Two.SET };
Set<String> set = Utils.immutableSetOf(mySet);

The reason this works is because, we create a new Set[] without specifying the generics type and assign it to the reference Set[] mySet (since this is an unchecked operation, we have to add @SuppressWarnings("unchecked") to it)

Problem

I have multiple `Set<String>` that I need to merge into one `Set<String>`. How do I do this operation in Java? Note, I am using using the `guava` API as best as I can to help out. For example, I have 3 classes as follows. ``` public class One { public static Set<String> SET = Sets.newHashSet("a","b","c"); } public class Two { public static Set<String> SET = Sets.newHashSet("a","d","e","f"); } public class Three { public static Set<String> SET = Sets.newHashSet("w","x","y","f"); } ``` Now, I need to merge any combination of these sets into one. For, example, I may need to merge - `One.SET` + `Two.SET` + `Three.SET` into one to produce { "a","b","c","d","e","f","w","x","y" }, - `One.SET` + `Three.SET` into one to produce { "a","b","c","w","x","y","f" }, - `Two.SET` + `Three.SET` into one to produce { "a","d","e","f","w","x","y" }, - and so on I created a method to merge an array of sets, `Set<String>[]`, but that doesn't work (explained here by this SO post Creating an array of Sets in Java). Here's the code to merge. It works (compiles). ``` public static Set<String> immutableSetOf(Set<String>[] sets) { Set<String> set = new HashSet<String>(); for(Set<String> s : sets) { set.addAll(s); } return ImmutableSet.copyOf(set); } ``` Here's the calling code; it doesn't work (doesn't compile). ``` Set<String> set = Utils.immutableSetOf(new Set<String>[] { One.SET, Two.SET }); ``` So, I modified my merging method to operate on `List<Set<String>>` instead of `Set<String>[]`. Only the argument type changed, but I put it here for completeness. ``` public static Set<String> immutableSetOf(List<Set<String>> sets) { Set<String> set = new HashSet<String>(); for(Set<String> s : sets) { set.addAll(s); } return ImmutableSet.copyOf(set); } ``` So, now my calling code looks like the following. ``` Set<String> set = Utils.immutableSetOf( Lists.newArrayList( One.SET, Two.SET)); ``` This code does not compile, since `Lists.newArrayList(...)` is returning `Set<String>` and not `List<Set<String>>`. The method `Lists.newArrayList(...)` is overloaded, and the signature of the method that is used when I pass in sets is, `List.newArrayList(Iterable<? extends E> elements)`. So, the question is, how do I define a method to merge an arbitrary number of `Set<String>` while considering the calling code? I note that the compilation problems are on the calling code (not the merging method), but perhaps the solution also relates to the merging code? Update: I also tried varargs but that produces its own warning (Is it possible to solve the "A generic array of T is created for a varargs parameter" compiler warning?). The merging method signature is now the following. ``` public static Set<String> immutableSetOf(Set<String>... sets) ``` The calling code is now the following, and I get "Type safety: A generic array of Set is created for a varargs parameter". ``` Set<String> set = Utils.immutableSetOf(One.SET, Two.SET); ``` Update: For the accepted answer, I did the following. ``` @SuppressWarnings("unchecked") Set<String> set = Utils.immutableSetOf(Set[] { One.SET, Two.SET }); ```

Original source

Related problems