性能:findIndex与Array.prototype.map

时间:2019-03-19 17:21:13

标签: javascript arrays dictionary object indexing

在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);

1 个答案:

答案 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>