我有以下功能用于统一多个集合(包括重复元素):
public static <T> List<T> unify(Collection<T>... collections) {
return Arrays.stream(collections)
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
对于集合的交集(使用类型相等),如果有一个具有相似签名的函数会很好。例如:
public static <T> List<T> intersect(Collection<T>... collections) {
//Here is where the magic happens
}
我找到了 intersect 函数的实现,但它不使用流:
public static <T> Set<T> intersect(Collection<? extends Collection<T>> collections) {
Set<T> common = new LinkedHashSet<T>();
if (!collections.isEmpty()) {
Iterator<? extends Collection<T>> iterator = collections.iterator();
common.addAll(iterator.next());
while (iterator.hasNext()) {
common.retainAll(iterator.next());
}
}
return common;
}
有什么方法可以利用流来实现类似于统一功能的功能吗?我在 java8/stream api 方面经验不足,因此一些建议会很有帮助。
最佳答案
您可以在一些实用程序类中编写自己的收集器并使用它:
public static <T, S extends Collection<T>> Collector<S, ?, Set<T>> intersecting() {
class Acc {
Set<T> result;
void accept(S s) {
if(result == null) result = new HashSet<>(s);
else result.retainAll(s);
}
Acc combine(Acc other) {
if(result == null) return other;
if(other.result != null) result.retainAll(other.result);
return this;
}
}
return Collector.of(Acc::new, Acc::accept, Acc::combine,
acc -> acc.result == null ? Collections.emptySet() : acc.result,
Collector.Characteristics.UNORDERED);
}
用法非常简单:
Set<T> result = Arrays.stream(collections).collect(MyCollectors.intersecting());
但是请注意,收集器不能短路:即使中间结果为空集合,它仍会处理流的其余部分。
这样的收集器在我的免费 StreamEx 中很容易获得。图书馆(见 MoreCollectors.intersecting()
)。它与上面的普通流一起工作,但如果你将它与 StreamEx(扩展普通流)一起使用,它就会短路:处理实际上可能会提前停止。
关于Java - 使用流 + lambdas 的多个集合的交集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42214519/