Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/418.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
Javascript 做集合减法的最快方法_Javascript_Actionscript 3_Performance - Fatal编程技术网

Javascript 做集合减法的最快方法

Javascript 做集合减法的最快方法,javascript,actionscript-3,performance,Javascript,Actionscript 3,Performance,我有两套集合b是集合a的子集。它们都是非常大的一组。 我想从a中减去b,做这个普通运算的最佳实践是什么? 我已经写了很多这样的代码,但我认为它效率不高。你的想法是什么 伪代码:(这不是JavaAPI) for(int i=0;i

我有两套<代码>集合b是集合a的子集。它们都是非常大的一组。 我想从a中减去b,做这个普通运算的最佳实践是什么? 我已经写了很多这样的代码,但我认为它效率不高。你的想法是什么

伪代码:(这不是JavaAPI)

for(int i=0;i
我想找到一个算法,不仅适用于集合,也适用于数组


编辑:这里的集合不是JavaAPI,它是一个数据结构。所以我不在乎Java API是否有removeAll()方法,我想为这个问题找到一个通用的解决方案,当我使用Javascript和Actionscript时,我遇到了很多类似的问题。

我认为你不会更快,但你的代码看起来会更简单,不会因为
a.removeAll(b)而变得更慢。是JavaAPI的一部分

对于效率分析:您给定的代码示例是O(n^2),它的伸缩性不是很好,但也不是地球上最可怕的事情(指数复杂性是您不想要的)。只要您不知道收集数据的内部组织,您就不会获得更好的性能。removeAll()由类本身实现,并且了解内部组织。因此,如果将数据组织在散列中,您可能会得到更好的结果,如果将数据组织在未排序的数组中,复杂性将是相同的。如果集合中已有新项,则集合必须有效地查找,因此我怀疑某种哈希是内部表示,特别是如果实现名为HashSet.:-)

编辑:OP改变了它的问题,提到它不仅适用于Java。removeAll()是一个Java API,因此它(或类似的东西)在其他语言中可能不可用。如前所述,如果集合是没有其他限制的未排序数组,那么两个for循环已经是最快的解决方案。但是,如果数据的组织方式不同,那么您就有了更快的选择。如果这两个集合是经过排序的数据(在我的示例中,最小的元素首先出现),则可以执行以下操作(将复杂性降低到O(n)):

int-bIndex=0;
对于(int i=0;i

如果数据在两个集合中都组织为散列,那么您也只需要一个for循环,直接访问b中的元素。其他可能的数据组织也是可能的。

您在Set界面中看到了removeAll方法吗


另外请查看。

我相信您会发现
java.util.HashSet.removeAll(Collection toRemove)
性能良好。
另一方面,如果您没有集合,但有已排序的集合,您可能会做得更好。

最后,除了逐个比较元素并删除两者中的元素之外,没有其他选择

换一种方法,你必须做一些奇特的事情,比如给所有集合成员一个唯一的值索引,然后构造一个表示每个集合的巨大布尔数组,然后你可以进行位运算,从a中减去B。我不知道这是否会更快,考虑到创建唯一值索引和操作非常大的位掩码的开销


我知道您不关心Java解决方案,但由于其他人推荐removeAll(),我想指出的是,它仍然在做本质上相同的事情。检查HashSet的源。

如果对集合进行维护,使元素在任何给定时间都可以按排序顺序使用,则可以对两个集合执行一次线性传递,并创建O(n)时间差。现在,同样是如果你可以免费获得元素的有序列表——也就是说,集合的维护(即添加元素和删除元素操作)支付了保持元素有序可用的成本

任何依赖于执行查找的“removeAll”操作都必然比O(n)更糟糕


(我突然想到,差集的构造——也就是从两个列表的线性传递构造的答案——如果你不非常小心的话,可能是O(n log n)。

好吧,正确的想法已经指出:应该使用哈希实现差集。哈希理想情况下具有
O(1)
访问成本,因此假设可以确定哪个集合更大(如在插入/删除操作期间维护计数器),则可以获得整个操作的
O(min(m,n))
成本

在ActionScript3中,您将使用。只需使用元素作为键和值

删除内容如下所示:

for each (var key:* in set2) {//a simple for-in loop will also do the trick, since keys and values are equal, but for-each-in loops perform faster
    delete set1[key];
}
for (var key in set2) {
    delete set1[key];
}
在JavaScript中,插入时需要提供条目ID,以便可以将这些ID用作映射中的键。只需将ID映射到原始值

删除内容如下所示:

for each (var key:* in set2) {//a simple for-in loop will also do the trick, since keys and values are equal, but for-each-in loops perform faster
    delete set1[key];
}
for (var key in set2) {
    delete set1[key];
}

假设b是a的子集,我不确定为什么伪代码有2个循环。我的想法是:

foreach b in B
    remove b from A

实际上,它的运行时与您的运行时相比如何,除其他外,取决于您如何将集合实现为数据结构。

编写时的操作是O(N^2),但如果集合较大,则可能需要使用哈希

// A is some kind of array, O(1) iteration
// B is a hash containing elements to remove, O(1) contains(elt)
List<T> removeAll(List<T> A, Set<T> B) {
  List<T> result; // empty, could preallocate at |A|
  for (elt : A) { // for each 'elt' belonging to A, hence O(|A|)
    if (! B.contains(elt) ) { // O(1) thanks to hash
      C.add(elt) ; // ensure this is O(1) with preallocation or linked list
    }
  }
  return result;
}
//A是某种数组,O(1)迭代
//B是包含要删除的元素的散列,O(1)包含(elt)
列表移除全部(列表A,集合B){
列表结果;//为空,可在| A处预分配|
对于(elt:A){//对于属于A的每个“elt”,因此O(| A |)
如果(!B.contains(elt)){//O(1),多亏了hash
C.add(elt);//确保这是O(1)