在2019年,如果我正在处理长度为15000以北的对象数组,则需要按值查找对象的索引,以下哪种方法将是我最佳的性能选择吗?
六岁的“答案”:In an array of objects, fastest way to find the index of an object whose attributes match a search
findIndex
array.findIndex(object => foo === object.id);
Array.prototype.map
array.map(object => object.id).indexOf(foo);
答案 0 :(得分:2)
从概念上讲,这两个摘要实现了相同的目标,但实现方式却截然不同。要了解两种解决方案的不同之处,我们首先来看一下findIndex
:
findIndex
方法对数组中的每个数组索引callback
(含)执行一次0..length-1
函数,直到找到callback
返回真实值的位置为止值。
强调我的
换句话说,它将在找到您要查找的商品后立即停止。 indexOf
具有类似的行为,因为它将返回找到的 first 项的索引。
另一方面,查看map
:
map
依次对数组中的每个元素调用一次provided
回调函数,并从结果中构造一个新数组 。
强调我的
换句话说,map
不在乎您要搜索的项目。即使您要查找的项目是数组中的第一项,map
仍将遍历其他14999个项目以创建id
的新数组。这意味着就时间复杂度(遍历所有这些项目需要更多的时间)和空间复杂度(需要更多的内存来存储该临时数组)而言,您将要做大量的工作来获得相同的结果。
旁注:如果您使用iterators / generators,上述内容不一定正确,从某种意义上说,它可以“向前看”,以查看是否需要做更多的工作。但是我认为这超出了这个问题的范围。
但是,如果您真的很担心性能,那么对自己进行测试始终是一个好主意。这是一个快速的基准测试,用于演示两种实现方式的相对性能。在我的机器上,我得到findIndex: 0.023ms
/ map+indexOf: 0.572ms
。您的里程可能会有所不同:
var suite = new Benchmark.Suite();
const haystack = [];
let needle;
suite
.add('findIndex', () => haystack.findIndex(o => o.id === needle))
.add('map+indexOf', () => haystack.map(o => o.id).indexOf(needle))
.on('start', () => {
for (let i = 0; i < 15000; i++) {
haystack.push({
id: Math.random().toString(36).substring(7)
});
}
console.log('Starting test.');
})
.on('cycle', () => {
needle = haystack[Math.floor(Math.random() * haystack.length)].id;
})
.on('complete', () => {
console.log('Test results (lower is better):')
suite.forEach((bench) => {
console.log(` ${bench.name}: ${(bench.stats.mean * 1000).toFixed(3)}ms`);
});
})
.run({
'async': true
});
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/platform/1.3.5/platform.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/benchmark/2.1.4/benchmark.min.js"></script>