我有多个
Set<String>
需要合并成一个Set<String>
。我如何在 Java 中执行此操作?请注意,我正在尽我所能使用 guava
API 来提供帮助。例如,我有 3 个类如下。
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");
}
现在,我需要将这些集合的任意组合合并为一个。例如,我可能需要合并
One.SET
+ Two.SET
+ Three.SET
合并为一个生成 { "a","b","c","d","e","f","w","x"," y" }, One.SET
+ Three.SET
合二为一产生 { "a","b","c","w","x","y","f" },Two.SET
+ Three.SET
合二为一产生 { "a","d","e","f","w","x","y" },我创建了一个方法来合并一组集合,
Set<String>[]
,但这不起作用(在 SO 帖子 Creating an array of Sets in Java 中解释)。这是要合并的代码。它有效(编译)。
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);
}
这是调用代码;它不起作用(无法编译)。
Set<String> set = Utils.immutableSetOf(new Set<String>[] { One.SET, Two.SET });
所以,我修改了我的合并方法来对
List<Set<String>>
而不是Set<String>[]
进行操作。只有参数类型发生了变化,但为了完整起见,我把它放在这里。
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);
}
所以,现在我的调用代码如下所示。
Set<String> set = Utils.immutableSetOf(
Lists.newArrayList(
One.SET, Two.SET));
此代码无法编译,因为
Lists.newArrayList(...)
返回的是 Set<String>
而不是 List<Set<String>>
。方法Lists.newArrayList(...)
被重载了,我传入集合时使用的方法的签名是,List.newArrayList(Iterable<? extends E> elements)
.
那么,问题是,在考虑调用代码的同时,如何定义一个方法来合并任意数量的
Set<String>
?我注意到编译问题出在调用代码上(而不是合并方法),但也许解决方案也与合并代码有关?
更新:我也尝试过 varargs 但它会产生自己的警告(是否有可能解决“为可变参数创建一个通用的 T 数组”编译器警告?)。合并方法签名现在如下。
public static Set<String> immutableSetOf(Set<String>... sets)
现在调用代码如下,我得到“类型安全:为可变参数参数创建了一个通用的集合数组”。
Set<String> set = Utils.immutableSetOf(One.SET, Two.SET);
更新:对于接受的答案,我做了以下事情。
@SuppressWarnings("unchecked")
Set<String> set = Utils.immutableSetOf(Set[] { One.SET, Two.SET });
推荐
com.google.common.collect.Sets#union(set1, set2)
进行合并,而不是 Set.addAll
在引擎盖下,因为番石榴已经在您的依赖项中。
原因:它是view,它是内存有效的,也是不可修改的。
加:我应该把它作为评论发布,对不起。
如何创建输入集的集合,然后使用
flatMap
?
Set<String> allElements = ImmutableSet.of(
One.SET,
Two.SET,
Three.SET
).stream().flatMap(Collection::stream).collect(Collectors.toSet());
在你之前的尝试中,你已经写了
Set<String> set = Utils.immutableSetOf(new Set<String>[] { One.SET, Two.SET });
这不起作用,因为在 java 中不允许创建泛型数组
试试这个:
@SuppressWarnings("unchecked")
Set<String>[] mySet = new Set[] { One.SET, Two.SET };
Set<String> set = Utils.immutableSetOf(mySet);
之所以可行,是因为我们创建了一个新的 Set[] 而没有指定泛型类型并将其分配给引用 Set[] mySet(因为这是一个未经检查的操作,我们必须添加 @SuppressWarnings("unchecked") 到它)
您可以使用:
Set<String> set = immutableSetOf(Arrays.asList(One.SET, Two.SET));
使用你对
immutableSetOf(List<Set<String>> sets)
的定义。没有警告或抑制警告。
我在想
FluentIterable
(在 18.0 及更高版本中)可以在这里提供帮助,特别是 append
方法。
有了这个,我们需要定义一个方便的辅助方法 - 是的,我们将为此使用可变参数。
public <T extends Comparable<T>> Set<T> mergeSets(Set<T> initial,
Set<T>... rest) {
FluentIterable<T> result = FluentIterable.from(initial);
for(Set<T> set : rest) {
result = result.append(set);
}
return new TreeSet<>(result.toSet());
}
这里的结果集是自然顺序的。如果您不想要
TreeSet
并且之后不想改变您的收藏,则省略 new TreeSet<>
部分,并放松 T
上的绑定。
这应该有帮助。 java8 中的在线器 -> Stream.of(sets).flatMap(Set::stream).collect(Collectors.toSet())