假设我们有一个包含重复项的数组:
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.如果没有,为什么?
答案 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