具有唯一值的数组:indexOf vs new Set

时间:2017-05-09 13:10:07

标签: javascript arrays

假设我们有一个包含重复项的数组:

var items = ['a', 'd', 'e', 'b', 'c', 'd', 'e', 'f', 'g', 'd', 'f', 'g', 'd', 'j', 'k', 'l', 'd', 'e', 'c', 'd', 'e', 'f', 'g', 'd','c', 'd', 'e', 'f', 'g', 'd'];

如果您必须遍历项目,那么拥有值的新数组的最快方法是什么(可能没有意义,但这就是场景)。

选项1:

var list = [];
items.forEach(function(item) {
    if(list.indexOf(item) == -1)
      list.push(item);
});

选项2:

var list = [];
items.forEach(function(item) {
    list.push(item);
});

list = Array.from(new Set(list));

现在我已经使用console.time进行了一些测试,它显示选项2比选项1快5倍。但我不确定这个console.time是多么值得信赖。 任何见解? indexOf是什么让选项1更慢?

小提琴:http://demos.jquerymobile.com/1.0rc1/docs/content/content-grids.html

编辑:另一个问题:如果选项2更快,我应该从选项1 =>更改我的代码吗?选项2.如果没有,为什么?

1 个答案:

答案 0 :(得分:2)

  

" indexOf是什么让选项1更慢?"

是。 indexOf是O(n)意味着你的循环中有一个循环给你整体O(n2)。 indexOf相当于做这样的事情:

function indexOf(item, array) {
    for (var i=0; i < array.length; i++) {
        if (array[i] === item) {
            return true;
        }
    }
    return false;
}

你可以看到,在更坏的情况下(项目已经不在数组中)迭代整个数组。没有办法绕过它。如果您在数组中搜索某个值,则必须查看每个项目,直到找到它或用完项目为止。

在选项2中查找集合中的值是O(1)而Array.from是O(n),因此整体上是O(n)。

制作一个集合在某种程度上等同于做这样的事情(这不是实际上不会产生一个集合,而是一个对象,所以它并不完全相同):

function makeSet(array) {
    var set = {};
    for (var i=0; i < array.length; i++) {
        if (set[array[i]] === undefined) {   // indexing `set` is O(1)
            set[array[i]] = true;
        }
    }
}

总体而言O(n)。从中创建数组只是迭代集合并将其加载到数组中的情况,该数组也是O(n)。所以它总体来说是O(n)

  

另一个问题:如果选项1更快,我应该从选项1 =&gt;更改我的代码吗?选项2.如果没有,为什么?

选项1不是更快,但如果我们假装它是,那么答案是它取决于。选项1肯定不会与选项2一起扩展,但这并不意味着选项1对于足够小的阵列可能不会更快(尽管我对此表示怀疑)。无论哪种方式,这都是过早的优化。如果您的代码运行缓慢,并且您分析了代码并将部分标识为瓶颈,那么您应该担心它。

编辑:

  

小错字,我的意思是如果选项2更快。没有瓶颈,

因此,关于过早优化的相同论点仍然适用。但就个人而言,我可能会改变它。这似乎是相当低的影响,如果有的话,可以说,可能有更明确的选择2的意图。

虽然 - 确实考虑了Set的浏览器支持。它相对较新,不受旧版浏览器的支持。 See here