在JavaScript中,如何最快地实现'countBy'?

mdfafbf1  于 2023-04-10  发布在  Java
关注(0)|答案(1)|浏览(160)

bounty还有3天到期。回答此问题可获得+50声望奖励。Sasgorilla希望引起更多关注此问题。

我需要迭代一个大的记录集,并计算特定字段中的不同值的数量:

>> const cats = [
    {name: 'Sophie', color: 'black'},
    {name: 'Moo',    color: 'grey'},
    {name: 'Tipper', color: 'black'}
  ]

>> countBy(cats, 'color')
Map('black' => 2, 'grey' => 1) # (precise data structure unimportant)

嘿,这就是lodash countBy的用途!但在我的应用程序中,性能是最重要的。在我的(非常非正式的)基准测试中,这段简单的代码比lodash高出约50%:

function countBy<R extends object>(records: R[], key: keyof R) {
  const counts = new Map<keyof R, number>()
  for (const i = 0; i < records.length; i++) {
    const value = records[i][key]
    counts.set(value, (counts.get(value) || 0) + 1)
  }
}

(This也许并不令人惊讶,因为它不需要处理比keyof R更高级的“迭代对象”。)
问:有没有什么方法可以在速度上打败这个算法?

2uluyalo

2uluyalo1#

这完全取决于我们要执行操作的数据量。我认为使用Lodashvanilla JS都是有效的方法。
但是在检查了JS性能基准测试工具的性能后,我发现Vanilla JS代码比Lodash代码更高效。
因此,出于演示和测试的目的,我使用Array.reduce()方法来计算cats数组中的颜色。

const cats = [
  {name: 'Sophie', color: 'black'},
  {name: 'Moo',    color: 'grey'},
  {name: 'Tipper', color: 'black'}
];

function countBy(arr, prop) {
    return arr.reduce((total, current) => {
    total[current[prop]] = (total[current[prop]] || 0) + 1;
    return total;
  }, {})
}

const result = countBy(cats, 'color');

console.log(result);

并将其与Lodash解决方案进行比较。

const cats = [
  {name: 'Sophie', color: 'black'},
  {name: 'Moo',    color: 'grey'},
  {name: 'Tipper', color: 'black'}
];

const result = _.countBy(cats, 'color')

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

我发现lodash比Vanilla JS慢。下面是来自jsbench的截图。

相关问题