我知道,在Java中,我可以手动确定两个集合是否有任何重叠,方法是将其中一个集合转换为一个集合,然后迭代另一个集合进行包含检查:
<T> boolean anyInCommon(Iterable<T> collection1, Set<T> collection2) {
for (T item : collection1)
if (collection2.contains(item))
return true;
return false;
}
或者:
<T> boolean anyInCommon(Iterable<T> collection1, Set<T> collection2) {
return collection1.stream().anyMatch(collection2::contains);
}
但是现有的实用方法是否可以做到这一点并智能地选择要迭代的集合,哪些集合变成集合,利用已经成为集合的集合等等?我知道Guava有Sets.intersection
,但是它会计算整个的交集,而不仅仅是它是否为空。
请注意,一旦找到任何常见项目,我宁愿将比较发生短路。检查两个巨大的集合是否有重叠应该花费时间与非重叠项目(或更好)的数量成比例,而不是项目的总数。
答案 0 :(得分:1)
当集合已经设置时的部分答案。
Sets.intersection
实际上比我想要的更接近,因为它的结果不是预先计算的。取而代之的是it's a view即时计算的交叉点。
看看the anonymous class returned by 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);
}
};
isEmpty
方法不会检查每个项目。相反,它会在检查项目是否在第二组中时迭代第一组。一找到它,它就会返回true。如果您运气不好,您将首先迭代set1中不在set2中的所有项目,但这可能是不可避免的,并且比总是迭代所有项目更好。
换句话说,如果你已经有了,那么恰当短路的有效解决方案就是:
boolean overlaps = !Sets.intersections(set1, set2).isEmpty();
这不会迭代较小的集合而不是较大的集合,或者处理非集合集合,但它通常很有用。