如何在Java中将多个(任意数量的)Set <string>合并为一个?</string>

时间:2014-12-03 04:22:36

标签: java collections guava

我需要将多个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,但会产生自己的警告(Is it possible to solve the "A generic array of T is created for a varargs parameter" compiler warning?)。合并方法签名现在如下。

public static Set<String> immutableSetOf(Set<String>... sets)

调用代码现在如下,我得到“类型安全:为varargs参数创建Set的通用数组”。

Set<String> set = Utils.immutableSetOf(One.SET, Two.SET);

更新:对于接受的答案,我做了以下内容。

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

5 个答案:

答案 0 :(得分:6)

建议com.google.common.collect.Sets#union(set1, set2)获取合并而不是Set.addAll,因为Guava已经在您的依赖项中。

原因:它的视图是内存有效的,也是不可修改的

加:我应该将其发布为评论,抱歉。

答案 1 :(得分:1)

在您之前的尝试中,您已写过

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(&#34) ;未选中&#34;)到它)

答案 2 :(得分:1)

您可以使用:

Set<String> set = immutableSetOf(Arrays.asList(One.SET, Two.SET));

使用您对immutableSetOf(List<Set<String>> sets)的定义。没有警告或抑制警告。

答案 3 :(得分:1)

我认为FluentIterable(18.0及以上)可以在这方面提供帮助,特别是append method

有了这个,我们需要定义一个方便的帮助方法 - 是的,我们将为此使用varargs。

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上的界限。

答案 4 :(得分:0)

如何创建输入集的集合,然后使用flatMap

Set<String> allElements = ImmutableSet.of(
        One.SET,
        Two.SET,
        Three.SET
).stream().flatMap(Collection::stream).collect(Collectors.toSet());