Java - 使用stream + lambdas交叉多个集合 [英] Java - Intersection of multiple collections using stream + lambdas

查看:107
本文介绍了Java - 使用stream + lambdas交叉多个集合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下函数来统一多个集合(包括重复元素):

I have the following function for the unification of multiple collections (includes repeated elements):

public static <T> List<T> unify(Collection<T>... collections) {
        return Arrays.stream(collections)
               .flatMap(Collection::stream)
               .collect(Collectors.toList()); 
}

拥有一个类似签名的函数会很好集合(使用类型相等)。例如:

It would be nice to have a function with a similar signature for the intersection of collections (using type equality). For example:

public static <T> List<T> intersect(Collection<T>... collections) {
     //Here is where the magic happens
}

我找到了交叉函数的实现,但它不使用流:

I found an implementation of the intersect function, but it doesnt use streams:

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

有没有办法实现与使用流的unify函数类似的东西?我在java8 / stream api中没那么有经验,因为一些建议会非常有帮助。

Is there any way to implement something similar to the unify function making use of streams? Im not so experienced in java8/stream api, because of that some advice would be really helpful.

推荐答案

你可以自己编写某个实用程序类中的收集器并使用它:

You can write your own collector in some utility class and use it:

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

但是请注意,收集器不能短路:即使中间结果是空集合,它也会仍然处理流的其余部分。

Note however that collector cannot short-circuit: even if intermediate result will be an empty collection, it will still process the rest of the stream.

这样的收集器可以在我的免费 StreamEx中找到库(参见 MoreCollectors.intersecting () )。它适用于上面的普通流,但是如果你将它与StreamEx(扩展普通流)一起使用,它就会变短路:处理实际上可能会提前停止。

Such collector is readily available in my free StreamEx library (see MoreCollectors.intersecting()). It works with normal streams like above, but if you use it with StreamEx (which extends normal stream) it becomes short-circuiting: the processing may actually stop early.

这篇关于Java - 使用stream + lambdas交叉多个集合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆