【问题标题】:JavaScript - remove duplicates algorithm efficiencyJavaScript - 删除重复算法效率
【发布时间】:2014-11-23 16:23:01
【问题描述】:

我已经阅读了很多关于这个主题的内容,并且看到了许多不同的算法。我偶然发现了另一个解决方案,与其他算法相比,我很难理解它的效率,因为它使用一个简单的临时对象来保存数组的现有元素。与使用复杂排序方法和比较的“老派”方法相比,这是一个有效的解决方案吗?

 function removeDup(arr){
        var element,
                existObj= {},
                finalArr = [];

        for(var i=0;i<arr.length;i++){
            element = arr[i];
            if(!existObj[element]){
                finalArr.push(element);
                existObj[element] = true;
            }
        }
        return finalArr;
    }
    //console.log(removeDup([2,2,2,2,4534,5,7,3]));
    console.log(removeDup(["mike","john","alex","mike","john"]));

有朋友告诉我,这里的效率无法明确确定,因为我真的不知道 temp 对象是如何实现的。

【问题讨论】:

  • existObj 视为哈希映射 - 具有接近 O(1) 的分配和访问性能。
  • 使用 Array.filter 更简单
  • @Bergi :你是对的,因为 O(1)+constant === 0(1),我们没有一个“接近”O(1) 的查找,而是 O (1)。所以这个算法是O(n)。现在,如我的回答所示,通过使用最适合的原生对象,我们可以在这个 O(n) 的“k”上获得 6-10 倍的改进。
  • @GameAlchemist:我不是在谈论常量。分配和访问哈希图中的元素将始终取决于 (k) 键的大小(例如属性字符串的长度)、(v) 存储值的大小和 (n) 映射中的项目数 - 只需非常好复杂性。 (免责声明:v 对于像这里这样的布尔值或对象指针是常量;k 可以通过不访问所有字节的惰性散列函数来减少;如果密钥空间有限,n 可能会受到限制)
  • @Bergi :我想检查 O(1) 是否足够好,所以我做了一个情节(见我的回答)。实际上 O(1) 是一个很好的近似值,即使价差随着 n 的增加而增加。

标签: javascript algorithm duplicate-removal


【解决方案1】:

通过使用最合适的数据结构,您将获得最佳性能。在像 js 这样的 JIT/解释型语言中,使用原生功能的好处是巨大的。

这是一个你应该首先使用的 Set:这样你甚至不需要做任何事情来删除 dup,它们只会在添加时被忽略。
我刚刚做了一个简单的测试,使用 Set 的性能大约快了六到十倍(!!)。

http://jsbin.com/jofofeyixaco/1/edit?js,console

结果示例:

"overhead is : 0.015700000221841037"
"Built unic numbers with a lookup object in : 6.237600000167731"
"Built unic numbers with a Set in : 0.7921500000520609"

以下是两种算法的 n = 0 到 50.000 的曲线。
我们看到哈希图的行为确实很像 O(1),但是当 n 增加时具有更高的散布。
Set 几乎是完全线性的。

画jsbin(耐心点!):http://jsbin.com/jofofeyixaco/2/

代码:

// noprotect
// build a test set
var numbers = [];
var cnt = 10000; 
for (var i=0; i<cnt; i++ ) numbers.push(Math.floor(Math.random*1000));

// build unic values using lookup object
function buildWithObject() {
  var existing= {};
  var unicNumbers = [];
  for (var i=0; i<cnt; i++) {
    var num = numbers[i];
    if (!existing[num]) {
      unicNumbers.push(num);
      existing[num]=true;
    }
  }
}

// build unic values using a Set
function buildWithSet() {
    var unicNumbersSet = new Set();
    for (var i=0; i<cnt; i++) {
         var num = numbers[i];
         unicNumbersSet.add(num);
    }  
}

function iterate() {
    for (var i=0; i<cnt; i++) {
         var num = numbers[i];
    }    
}

// warming up functions
for (var i=0; i<30; i++) { buildWithObject(); buildWithSet() ;  iterate(); }

// --------  Measures  --------------------
var measureRepeat = 20;
var m;

var s,e;
// ----------------------------
m=measureRepeat;
s=window.performance.now();
while (m--) iterate();
e=window.performance.now();

console.log('overhead is : ' + (e-s)/measureRepeat);

// ----------------------------
m=measureRepeat;
s=window.performance.now();
while (m--) buildWithObject();
e=window.performance.now();

console.log('Built unic numbers with a lookup object in : ' + (e-s)/measureRepeat);

// ----------------------------
m=measureRepeat;
s=window.performance.now();
while (m--) buildWithSet();
e=window.performance.now();
console.log('Built unic numbers with a Set in : ' + (e-s)/measureRepeat);

(别忘了,Set 是 EcmaScript 6,所以在 js 标签中使用 type="application/javascript;version=1.7"

如果您担心兼容性:http://kangax.github.io/compat-table/es6/#Set
所有“现代”平台都可以:Ch、FF、IE11、OS8
其他都不好。 )

【讨论】:

  • 嗯,是的,我担心Set的兼容性。
  • @Bergi :是的,这可能是一个问题,具体取决于您的目标。我更新以总结兼容性表。 (但在几个月内一切都会好起来的,因为 Harmony (不知何故)受到所有人的欢迎)。
  • 感谢您的出色回答。综上所述,假设使用对象作为查找图是正确的并且复杂度为 O(N) 是否正确。但是,使用 Set 会快很多,但是复杂度还是 O(N)?
  • 是的,如您所知,O(N) 表示 k*n+ctte,而 Set 的 k 常数大约小 10 倍。
【解决方案2】:
let existing = {};
let unicNumbers = [];   
arr.forEach((item) => {
        if (!existing[item.id]) {
            unicNumbers.push(item);
            existing[item.id] = true;
        }
    })

【讨论】:

  • 虽然此代码可能会为问题提供解决方案,但最好添加有关其工作原理/方式的上下文。这可以帮助未来的用户学习并将这些知识应用到他们自己的代码中。在解释代码时,您也可能会以赞成票的形式从用户那里获得积极的反馈。
猜你喜欢
  • 2014-08-25
  • 2010-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多