Java 中有效判断两个集合是否有共同项

Cra*_*ney 6 java collections intersection set

我知道,在 Java 中,我可以手动确定两个集合是否有重叠,方法是将其中一个集合转换为集合,然后迭代另一个集合,进行包含检查:

<T> boolean anyInCommon(Iterable<T> collection1, Set<T> collection2) {
    for (T item : collection1)
        if (collection2.contains(item))
            return true;
    return false;
}
Run Code Online (Sandbox Code Playgroud)

或者:

<T> boolean anyInCommon(Iterable<T> collection1, Set<T> collection2) {
    return collection1.stream().anyMatch(collection2::contains);
}
Run Code Online (Sandbox Code Playgroud)

但是,是否存在现有的实用方法可以执行此操作并智能地选择要迭代的集合、将哪些集合转变为集合、利用已经是集合的集合等?我知道 Guava 有Sets.intersection,但它计算整个交集,而不是仅仅计算它是否为空。

请注意,我更喜欢在发现任何常见项目后立即进行比较而不是短路。检查两个巨大的集合是否重叠所花费的时间应该与非重叠项目的数量(或更好)成正比,而不是与项目总数成正比。

Cra*_*ney 3

当集合已经是集合时的部分答案。

Sets.intersection实际上比我想象的更接近我想要的,因为它的结果不是预先计算的。相反,它是动态计算的交集视图

看一下返回的匿名类intersection

final Predicate<Object> inSet2 = Predicates.in(set2);
return new SetView<E>() {
  @Override public Iterator<E> iterator() {
    return Iterators.filter(set1.iterator(), inSet2);
  }
  @Override public int size() {
    return Iterators.size(iterator());
  }
  @Override public boolean isEmpty() {
    return !iterator().hasNext();
  }
  @Override public boolean contains(Object object) {
    return set1.contains(object) && set2.contains(object);
  }
  @Override public boolean containsAll(Collection<?> collection) {
    return set1.containsAll(collection)
        && set2.containsAll(collection);
  }
};
Run Code Online (Sandbox Code Playgroud)

isEmpty方法并未涵盖所有项目。相反,它会迭代第一个集合,同时检查项目是否在第二个集合中。一旦找到,它就会返回 true。如果你运气不好,你将首先迭代 set1 中不在 set2 中的所有项目,但这可能是不可避免的,并且比总是迭代所有项目要好。

换句话说,如果您已经有 set,则适当短路的有效解决方案就是:

boolean overlaps = !Sets.intersections(set1, set2).isEmpty();
Run Code Online (Sandbox Code Playgroud)

这不会迭代较小的集合而不是较大的集合,也不会处理非集合集合,但它通常很有用。