Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java中高效地计算两个集合的交集?_Java_Performance_Optimization_Set - Fatal编程技术网

在Java中高效地计算两个集合的交集?

在Java中高效地计算两个集合的交集?,java,performance,optimization,set,Java,Performance,Optimization,Set,在Java中,找到两个非稀疏集的交集大小的最有效方法是什么?这是一个操作,我将在大型设备上多次调用,因此优化非常重要。我无法修改原始集 我已经看过Apache Commons CollectionUtils.intersection,它看起来相当慢。我目前的方法是取两个集合中较小的集合,克隆它,然后在两个集合中较大的集合上调用.retainal public static int getIntersection(Set<Long> set1, Set<Long> set2

在Java中,找到两个非稀疏集的交集大小的最有效方法是什么?这是一个操作,我将在大型设备上多次调用,因此优化非常重要。我无法修改原始集

我已经看过Apache Commons CollectionUtils.intersection,它看起来相当慢。我目前的方法是取两个集合中较小的集合,克隆它,然后在两个集合中较大的集合上调用.retainal

public static int getIntersection(Set<Long> set1, Set<Long> set2) {
    boolean set1IsLarger = set1.size() > set2.size();
    Set<Long> cloneSet = new HashSet<Long>(set1IsLarger ? set2 : set1);
    cloneSet.retainAll(set1IsLarger ? set1 : set2);
    return cloneSet.size();
}
publicstaticintgetcrossion(Set set1,Set set2){
布尔值set1IsLarger=set1.size()>set2.size();
Set cloneSet=newhashset(set1IsLarger?set2:set1);
复盖cloneSet.Retainal(Set1Slarger?set1:set2);
返回cloneSet.size();
}

集合的成员是否可以轻松映射到相对较小的整数范围?如果是,考虑使用位集。然后,交集是按位的,一次是s-32个潜在成员。

只需使用的方法。

这是一个很好的方法。您应该从当前解决方案中获得O(n)性能

使用发布的方法运行一些测试,而不是构建一个新的HashSet。也就是说,让
A
为较小的集合,
B
为较大的集合,然后,对于
A
中的每个项目,如果它也存在于B中,则将其添加到C(一个新的哈希集)——仅为了计数,可以跳过中间的C集合

正如发布的方法一样,这应该是成本上的
O(| a |)
,因为迭代是
O(| a |)
,而对B的探索是
O(1)
。我不知道它将如何与克隆和删除方法进行比较

快乐编码——并发布一些结果;-)



事实上,进一步思考,我相信这比文章中的方法有更好的界限:
O(| A |)
vs
O(| A |+| B |)
。我不知道这是否会在现实中产生任何差异(或改进),我只希望当
|A |两个集合都可以排序时,它才是相关的,比如
TreeSet
运行两个迭代器可以更快地计算共享对象的数量


如果您经常执行此操作,如果您可以包装集合,以便缓存交叉点操作的结果,保留
dirty
标记以跟踪缓存结果的有效性,并在需要时重新计算,则可能会带来很多好处。

您可以使用Set方法retainal()避免所有手动工作

从文档:

s1.Retainal(s2)-将s1转换为s1和s2的交点。(两个集合的交集是仅包含两个集合共有的元素的集合。)


仅供参考,如果任何集合都使用相同的比较关系进行排序,则可以在时间N*M中迭代它们的交集,其中N是最小集合的大小,M是集合的数量

实现留给读者作为练习

使用Java 8流:

set1.stream().filter(s -> set2.contains(s)).collect(Collectors.toList());

如果计算交集只是为了计算集合中有多少元素,我建议您只需要直接计算交集,而不是构建集合,然后调用
size()

我的计数功能:

/**
 * Computes the size of intersection of two sets
 * @param small first set. preferably smaller than the second argument
 * @param large second set;
 * @param <T> the type
 * @return size of intersection of sets
 */
public <T> int countIntersection(Set<T> small, Set<T> large){
    //assuming first argument to be smaller than the later;
    //however double checking to be sure
    if (small.size() > large.size()) {
        //swap the references;
        Set<T> tmp = small;
        small = large;
        large = tmp;
    }
    int result = 0;
    for (T item : small) {
        if (large.contains(item)){
            //item found in both the sets
            result++;
        }
    }
    return result;
}
/**
*计算两个集合的交集的大小
*@param small第一套。最好小于第二个参数
*@param大第二套;
*@param类型
*@集合交集的返回大小
*/
公共int计数交叉口(设置为小,设置为大){
//假设第一个参数小于后一个参数;
//不过,请仔细检查以确保
if(small.size()>large.size()){
//交换参考文献;
设置tmp=小;
小=大;
大=tmp;
}
int结果=0;
用于(T项目:小型){
if(大型包含(项目)){
//在两个集合中都找到了项
结果++;
}
}
返回结果;
}

通过流计算交叉点/reduce(它假设您在调用之前先计算出哪个集合更大):

public int countIntersect(设置大集合,设置小集合){
返回smallerSet.stream().reduce(0,(a,b)->largerSet.contains(b)→a+1:a);
}

然而,我在其他地方读到,没有任何java代码能够比Set操作的Set方法更快,因为它们是作为本机代码而不是java代码实现的。因此,我支持尝试BitSet以获得更快的结果的建议。

+1同意,尽管在幕后,它几乎与OP的方法一样,尽管没有复制。你知道这一方法的效率吗?@Ina它是开源的,所以你可以自己看看:哦,谷歌。有多少问题以“做X最有效的方法是什么”开始,以Google Guava结束?据我所知,CollectionUtils.Intersection是一种更通用的方法(也可以应用于列表),这就是为什么它不适用于集合。您应该检查:布尔值的
size()
是多少?:-)如果用一个if语句代替三个
?:
语句,这可能会稍微快一点(极端微观优化)。这样,它只需要分支一次(可能很昂贵),而不是三次。我用这两种方法进行了测试,没有发现任何区别——也许编译器或运行时正在为我处理这一问题。如果没有任何信息,我们谈论的是哪种类型的集合,这个问题很难明确回答。不同的场景对于不同的动作有不同的成本。这取决于我们谈论的场景类型。您的复杂性似乎假设了一个哈希集,在这种情况下,我同意我们不能比that@Voo是的,我确实假设了一个哈希集——很好的调用。(以上所有帖子都假设一个哈希集。)感谢您做了所有这些分析。但是为了改进你的答案,你真的能发布在你的基准测试中获胜的方法吗(例如MyMethod1),这将使人们不必阅读thr
set1.stream().filter(s -> set2.contains(s)).collect(Collectors.toList());
/**
 * Computes the size of intersection of two sets
 * @param small first set. preferably smaller than the second argument
 * @param large second set;
 * @param <T> the type
 * @return size of intersection of sets
 */
public <T> int countIntersection(Set<T> small, Set<T> large){
    //assuming first argument to be smaller than the later;
    //however double checking to be sure
    if (small.size() > large.size()) {
        //swap the references;
        Set<T> tmp = small;
        small = large;
        large = tmp;
    }
    int result = 0;
    for (T item : small) {
        if (large.contains(item)){
            //item found in both the sets
            result++;
        }
    }
    return result;
}
public int countIntersect(Set<Integer> largerSet, Set<Integer> smallerSet){
    return smallerSet.stream().reduce(0, (a,b) ->  largerSet.contains(b)?a+1:a);
}