Java 8 集合流到新集合的交集

Java 8 集合流到新集合的交集,java-8,java-stream,Java 8,Java Stream,有没有更好、更简单的方法来解决这个问题 @Test public void testReduce() { Set<Integer> foo = ImmutableSet.of(1,2,3,4,8,9); Set<Integer> bar = ImmutableSet.of(1,3,8,5,11); //DO think about solution for 1..n sets, and not only two. Set<Integ

有没有更好、更简单的方法来解决这个问题

@Test
public void testReduce() {
    Set<Integer> foo = ImmutableSet.of(1,2,3,4,8,9);
    Set<Integer> bar = ImmutableSet.of(1,3,8,5,11);

    //DO think about solution for 1..n sets, and not only two.
    Set<Integer> intersection = ImmutableList.of(foo,bar)
            .stream()
            .reduce( null, (a, b) -> {
                if ( a == null ) {
                    a = new HashSet<Integer>(b);
                }
                else {
                    a.retainAll(b);
                }
                return a;
            });
    assertThat( intersection, is( ImmutableSet.of( 1,3,8) ) );
}
@测试
公共void testReduce(){
Set foo=ImmutableSet.of(1,2,3,4,8,9);
设置条=不可变设置(1,3,8,5,11);
//一定要考虑1..n个集合的解,而不仅仅是两个。
设置交叉点=不可变列表(foo,bar)
.stream()
.reduce(空,(a,b)->{
如果(a==null){
a=新哈希集(b);
}
否则{
a、 保留(b);
}
返回a;
});
断言(交集,is(1,3,8的不可变集));
}

您可以通过检查
foo
的元素是否在
bar
otherBar
集合中来过滤这些元素:

Set<Integer> set =
    foo.stream().filter(e -> Stream.of(bar, otherBar).allMatch(s -> s.contains(e))).collect(toSet());
Set=
foo.stream().filter(e->stream.of(bar,otherBar).allMatch(s->s.contains(e)).collect(toSet());
例如,如果您收到如您所述的
集合

public static <T> Set<T> intersection(Collection<Set<T>> input) {
    if(input.isEmpty()) {
        return Collections.emptySet();
    } else {
        Set<T> first = input.iterator().next();
        //if the collection allows to remove element, you can remove first before
        return first.stream().filter(e -> input.stream().allMatch(s -> s.contains(e))).collect(toSet());
    }
}
公共静态集合交叉点(集合输入){
if(input.isEmpty()){
返回集合;
}否则{
Set first=input.iterator().next();
//如果集合允许删除元素,则可以先删除,然后再删除
返回first.stream().filter(e->input.stream().allMatch(s->s.contains(e)).collect(toSet());
}
}

reduce
是错误的方法,因为不允许以这种方式修改函数的参数。这是一种可变的缩减,也称为
collect

List<Set<Integer>> listOfSets=…;
//check if at least one set is in the list
Set<Integer> intersection = listOfSets.stream().skip(1)
    .collect(()->new HashSet<>(listOfSets.get(0)), Set::retainAll, Set::retainAll);
列表集合=…;
//检查列表中是否至少有一组
Set intersection=listOfSets.stream().skip(1)
.collect(()->newhashset(listOfSets.get(0)),Set::retainal,Set::retainal);

必须查看第一个集合在这里是一个缩进,但是使用
null
作为标识值也不是干净的(并且不适用于
collect
,因为累加器无法返回新集合)。

此答案仅适用于整数集合,而不是通用集合。但对于追求速度的人来说,有时整数列表是压缩位图的好例子。您应该检查您的整数分组是否正确,在某些情况下,如果您这样做,您可以在速度上赢得几个数量级(使用com.googlecode.javaewah32,Apache 2.0许可证):

另一种选择是使用还原收集器:

EWAHCompressedBitmap32 res = sets.stream().collect(Collectors.reducing(
      //identity
      null, 
      //mapper set -> compressedBitmap
      l -> { 
          EWAHCompressedBitmap32 b = new EWAHCompressedBitmap32();
          l.stream().forEach(b::set);
          return b;
      },
      //and-reducer 
      (l, r) -> l == null ? r : l.and(r) 
 ));

如果您使用,以下功能将起作用:

在Eclipse集合中,
ImmutableSet
不扩展
java.util.Set
,因为
Set
是一个可变接口
MutableSet
扩展了
java.util.Set
。此设计选择在对此的回答中进行了解释


注意:我是Eclipse集合的提交者。

而不是
ImmutableList.of(foo,bar).stream()
你可以简单地使用
stream.of(foo,bar)
…@Wilson:我看到了这个问题。我需要一个河流交叉口,不是两个only@Holger:谢谢。这只是一个示例代码。在实际代码中,我希望输入一组集合。在示例中,我有两组集合。该解决方案应适用于任意数量的元素,并应避免每次运行reducer时创建新的集合。哇。很好的解决方案。一个问题:我们可以跳过流中的第一个元素。有可能吗?因为你要走十字路口,
skip(1)
不是真的需要,但性能稍微好一点。对于较大的流,除非第一个集合的元素比其他集合多得多,否则差异可以忽略不计。很好的例子。我将看一看Eclipse集合。看起来很有趣。
    Set<Integer> foo = ImmutableSet.of(1,2,3,4,8,9);
    Set<Integer> bar = ImmutableSet.of(1,3,8,5,11);

    List<Set<Integer>> sets = ImmutableList.of(foo,bar);

    EWAHCompressedBitmap32 res = sets.stream().map(l -> {
        EWAHCompressedBitmap32 b = new EWAHCompressedBitmap32();
        l.stream().forEach(b::set);
        return b;
    }).reduce(null, (l, r) -> l == null ? r : l.and(r));

    System.out.println(res);
EWAHCompressedBitmap32 res = sets.stream().collect(Collectors.reducing(
      //identity
      null, 
      //mapper set -> compressedBitmap
      l -> { 
          EWAHCompressedBitmap32 b = new EWAHCompressedBitmap32();
          l.stream().forEach(b::set);
          return b;
      },
      //and-reducer 
      (l, r) -> l == null ? r : l.and(r) 
 ));
@Test
public void testReduce()
{
    ImmutableSet<Integer> foo = Sets.immutable.of(1, 2, 3, 4, 8, 9);
    ImmutableSet<Integer> bar = Sets.immutable.of(1, 3, 8, 5, 11);

    // Works with Eclipse Collections 7.0 or above
    ImmutableSet<Integer> intersection1 = Lists.mutable.of(foo, bar)
            .stream()
            .reduce(ImmutableSet::intersect).get();
    Assert.assertEquals(intersection1, Sets.immutable.of(1, 3, 8));

    // Works with Eclipse Collections 8.0.0-M1 or above
    ImmutableSet<Integer> intersection2 = Lists.immutable.of(foo, bar)
            .reduce(ImmutableSet::intersect).get();
    Assert.assertEquals(intersection2, Sets.immutable.of(1, 3, 8));
}
@Test
public void testReduce()
{
    MutableSet<Integer> foo = Sets.mutable.of(1, 2, 3, 4, 8, 9);
    MutableSet<Integer> bar = Sets.mutable.of(1, 3, 8, 5, 11);

    // Works with Eclipse Collections 7.0 or above
    MutableSet<Integer> intersection1 = Lists.mutable.of(foo, bar)
            .stream()
            .reduce(MutableSet::intersect).get();
    Assert.assertEquals(intersection1, Sets.immutable.of(1, 3, 8));

    // Works with Eclipse Collections 8.0.0-M1 or above
    MutableSet<Integer> intersection2 = Lists.immutable.of(foo, bar)
            .reduce(MutableSet::intersect).get();
    Assert.assertEquals(intersection2, Sets.immutable.of(1, 3, 8));
}