使用Java流设置联合和交叉点

时间:2019-03-13 09:24:56

标签: java java-8 set java-stream

我目前有一个Java程序,该程序使用嵌套的for循环来计算一组整数列表的并集和交集。如何使用java parallel 流执行此操作?我目前拥有的代码如下

for(Set<Integer> x : listA) {
  for (Set<Integer> y : listB) {
       Set u = Sets.union(x,y); // Uses Guava library
       Set i = Sets.intersection(x,y);
  }
}

由于listA和listB很大,所以我想加快速度。

4 个答案:

答案 0 :(得分:2)

您不需要流来进行联合,但是,您可以将其用于交集,例如:

Set<Integer> setA = new HashSet<>(Arrays.asList(1,2,3));
Set<Integer> setB = new HashSet<>(Arrays.asList(2,3,4));
Set<Integer> union = new HashSet<>();
union.addAll(setA);
union.addAll(setB);

Set<Integer> intersection = setA.parallelStream()
        .filter(setB::contains)
        .collect(Collectors.toSet());

System.out.println("Union : " + union);
System.out.println("Intersection : " +intersection);

更新

以上代码使用Java的本机库和streams查找交集和并集。但是,如果您有一组集合,则可以将上述代码包装在函数中,然后从stream进行调用,以迭代两个列表,例如:

private static void unionAndIntersection(Set<Integer> setA, Set<Integer> setB) {
    Set<Integer> union = new HashSet<>();
    union.addAll(setA);
    union.addAll(setB);

    Set<Integer> intersection = setA.parallelStream()
            .filter(setB::contains)
            .collect(Collectors.toSet());

    System.out.println("Union : " + union);
    System.out.println("Intersection : " +intersection);
}

public static void main(String[] args){ 
    List<Set<Integer>> listA = new ArrayList<>();
    List<Set<Integer>> listB = new ArrayList<>();
    listA.stream()
        .forEach(a -> {
            listB.stream()
            .forEach(b -> unionAndIntersection(a, b));
        });
}

答案 1 :(得分:2)

如果确保像类TreeSet那样对y(和x)进行了排序,则以下代码将使用特殊的合并(内部方法addAllForTreeSet)。

for (Set<Integer> x : listA) {
    for (SortedSet<Integer> y : listB) {
        SortedSet<Integer> u = new TreeSet(x);
        u.addAll(y);
        SortedSet<Integer> i = new TreeSet(x);
        i.retainAll(y);
    }
}

我不确定这实际上是否更快。

更好的是,如果整数不是太通配(限于10_000)。如果这些值是非负数,则可以立即使用BitSet代替Set<Integer>

这是无与伦比的。使用可能的容量(例如10_000)的BitSet构造函数。

for (BitSet x : listA) {
    for (BitSet y : listB) {
        BitSet u = x.clone();
        u.or(y);
        BitSet i = x.clone();
        i.and(y);
    }
}

Ý您可能会使用并行流来节省等于处理器数量的因数。

listA.parallelStream().forEach(x -> {});

这是次要的优化。

我过去几年没有使用过的番石榴,它没有原始类型int的集合吗?

答案 2 :(得分:1)

值得注意的是,您不必将流用于联合和相交。 retainAll方法仅保留此集合中包含在指定集合中的元素:

Set<Integer> setA = new HashSet<>(Arrays.asList(1,2,3));
Set<Integer> setB = new HashSet<>(Arrays.asList(2,3,4));

setA.retainAll(setB);  // now setA has intersection

答案 3 :(得分:1)

交叉点:

List<T> intersect = list1.stream()
                         .filter(list2::contains)
                         .collect(Collectors.toList());

联盟:

List<T> union = Stream.concat(list1.stream(), list2.stream())
                                    .distinct()
                                    .collect(Collectors.toList());