【问题标题】:How to concisely spread array of objects by ID?如何通过 ID 简洁地分布对象数组?
【发布时间】:2019-08-31 07:34:42
【问题描述】:

我有一个项目数组:

const arr = [
  { id: 'abc', value: 2 },
  { id: 'def', value: 3 },
];

我想通过id创建一个项目对象:

const obj = {
  abc: { id: 'abc', value: 2 },
  def: { id: 'def', value: 3 },
};

据我所知,最高效、最简洁的方法是通过Array.prototype.reduce

const obj = arr.reduce((obj, entry) => {
  obj[entry.id] = entry;
  return obj;
}, {});

是否有更高效更简洁的方式来执行操作?它们是什么?

我知道这是相对主观的,我愿意接受如何更好地表达这个问题的建议。谢谢。

【问题讨论】:

  • “performant”和“concise”有时会互相交换。 .reduce() 方法涉及每个数组元素的函数调用,而简单的 for 循环则不会。
  • @Pointy 我相信 V8 引擎可能会优化并将函数转换为 C++ 中的低级关系,但这是随机猜测
  • 确实;除非规模很大,否则担心这样的事情通常是不值得的,然后算法优化通常比实现优化更有价值。
  • 就像“Erlang 先生”Joe Armstrong 常说的那样:“尽你所能写出最漂亮的代码。”

标签: javascript ecmascript-6 iteration


【解决方案1】:

您可以使用comma operator

const arr = [
  { id: 'abc', value: 2 },
  { id: 'def', value: 3 },
];

const obj = arr.reduce((obj, entry) => (obj[entry.id] = entry, obj), {});

console.log(obj);

它的可读性较差,但更简洁。这取决于你是否值得。既然您提到您对spread 感兴趣,这就是解决方案,但请参阅下面的性能:

const arr = [
  { id: 'abc', value: 2 },
  { id: 'def', value: 3 },
];

const obj = arr.reduce((obj, entry) => ({ ...obj, [entry.id]: entry }), {});

console.log(obj);

另一个使用Object.assign 传播参数的解决方案,但这段代码对我来说有点笨拙,请看下面的性能:

const arr = [
  { id: 'abc', value: 2 },
  { id: 'def', value: 3 },
];

const obj = Object.assign({}, ...arr.map(a => ({ [a.id]: a })));

console.log(obj);

至于性能最高的解决方案,for-loops 很难被击败:

const arr = [
  { id: 'abc', value: 2 },
  { id: 'def', value: 3 },
];

const obj = {}, len = arr.length;
for(let i = 0; i < len; i++) {
  let a = arr[i];
  obj[a.id] = a;
}

console.log(obj);

我机器上的快速基准测试给出了以下结果(在 Firefox 66 上):

test case     | ops/s             | result
reduce-comma  | 22,248,622 ±2.83% |  6.89% slower
reduce-spread |  4,149,590 ±2.84% | 82.63% slower
object-assign |  1,809,170 ±0.69% | 92.43% slower
for-loop      | 23,895,193 ±2.51% | fastest

由于使用了对象扩展运算符,第二种解决方案要慢得多,该运算符在每次迭代时都会克隆对象。老实说,我不确定为什么 Object.assign 会更慢,因为大多数对象传播的实现都只是 Object.assign 在幕后。

最后两个选项之间的区别是微乎其微的,但在优化不那么好的旧浏览器上可能更显着。如果这确实是一个性能关键的应用程序,我建议您运行自己的基准测试。

【讨论】:

  • 隐式返回很好
  • 我正在寻找隐式返回以外的其他东西,可能是扩展运算符、函数生成器、迭代器、es7 等,但谢谢你的回答
  • @neaumusic 我添加了一个使用对象传播的解决方案。 IMO,就可读性和性能而言,这不是一个好的解决方案。我个人的偏好是带逗号的 reduce 或您的原始代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-16
  • 1970-01-01
  • 2021-09-04
  • 2019-08-26
  • 1970-01-01
  • 1970-01-01
  • 2011-09-20
相关资源
最近更新 更多