简体   繁体   English

用唯一键将对象数组转换为对象的最有效方法是什么

[英]What is the most performant way to convert an Array of Object to an Object with unique keys

I am trying to figure out the most performant Javascript way to convert an array of objects, into an object with unique keys and an array full of objects as the value. 我试图找出最高性能的Javascript方法,将对象数组转换为具有唯一键的对象,并使用充满对象的数组作为值。

For Example: 例如:

const array = [
  { "name": "greg", "year": "2000" },
  { "name": "john", "year": "2002" },
  { "name": "bob",  "year": "2005" },
  { "name": "ned",  "year": "2000" },
  { "name": "pam",  "year": "2000" },
];

I would like this converted to: 我希望将其转换为:

{
  "2000": [ 
    { "name": "greg", "year": "2000" }, 
    { "name": "ned",  "year": "2000" },
    { "name": "pam",  "year": "2000" }
  ],
  "2002": [ { "name": "john", "year": "2002" } ],
  "2005": [ { "name": "bob",  "year": "2005" } ],
}

As of now, this is what I've done so far: 到目前为止,这是我到目前为止所做的:

let yearsObj = {};

for (let i=0; i<array.length; i++) {
  if (!yearsObj[array[i].year]) {
    yearsObj[array[i].year] = [];
  }

  yearsObj[array[i].year].push(array[i]);
}

you can use a more elegant way to do it by using array's reduce function 您可以通过使用数组的reduce函数,以更优雅的方式实现此目的

// # impl


const group = key => array =>
  array.reduce(
    (objectsByKeyValue, obj) => ({
      ...objectsByKeyValue,
      [obj[key]]: (objectsByKeyValue[obj[key]] || []).concat(obj)
    }),
    {}
  );

// # usage 

console.log(
  JSON.stringify({
    byYear: group(array),
  }, null, 1)
);

// output //输出

VM278:1 { "carsByBrand": { "2000": [ { "name": "greg", "year": "2000" }, { "name": "ned", "year": "2000" }, { "name": "pam", "year": "2000" } ], "2002": [ { "name": "john", "year": "2002" } ], "2005": [ { "name": "bob", "year": "2005" } ] } } VM278:1 {“ carsByBrand”:{“ 2000”:[{“ name”:“ greg”,“ year”:“ 2000”},{“ name”:“ ned”,“ year”:“ 2000”}, {“ name”:“ pam”,“ year”:“ 2000”}],“ 2002”:[{“ name”:“ john”,“ year”:“ 2002”}],“ 2005”:[{“名称”:“鲍勃”,“年份”:“ 2005”}}}}

It could be as simple as that Object.fromEntries(array.map(obj => [obj.year,obj])) even it is not exactly what you need, but talking about performance it is way slower than all proposed, so i'm giving it as an bad example of showing how the short statement is not always the fastest. 它可能就像Object.fromEntries(array.map(obj => [obj.year,obj]))一样简单,即使它不是您所需要的,但是谈论性能却比所有建议的都要慢,所以我给出了一个不好的例子,表明简短的陈述并非总是最快的。 Your way seems to be the fastest taking about performance. 您的方式似乎是最快的性能。 Run the snippet below to see the actual timing. 运行下面的代码片段以查看实际时间。

 // common let array = [ { "name": "greg", "year": "2000" }, { "name": "john", "year": "2002" }, { "name": "bob", "year": "2005" }, { "name": "ned", "year": "2000" }, { "name": "pam", "year": "2000" }, ]; // simple as a statement way console.time(); console.log(Object.fromEntries(array.map(obj => [obj.year,obj]))); console.timeEnd(); // using .reduce way console.time(); const result = array.reduce((prev, curr) => { const { year } = curr; if (prev[year]) { prev[year].push(curr); } else { prev[year] = [curr]; } return prev; }, {}); console.log(result); console.timeEnd(); // your way console.time(); let yearsObj = {}; for (let i=0; i<array.length; i++) { if (!yearsObj[array[i].year]) { yearsObj[array[i].year] = []; } yearsObj[array[i].year].push(array[i]); } console.log(yearsObj); console.timeEnd(); 

A for loop (imperative style) like you have is likely to be the fastest in most situations. 在大多数情况下,像您这样的for循环(命令式)可能是最快的。 However, in this case you are not likely to see much of a difference. 但是,在这种情况下,您不太可能看到很大的不同。 One thing you could do to improve the code in your example is to get the array length before the for loop and assign it to the variable, so that it's not calculated every iteration of the loop. 您可以在示例中改善代码的一件事是在for循环之前获取数组长度并将其分配给变量,这样就不必在每次循环迭代时都计算出数组长度。

const yearsObj = {};
const arrayLength = array.length; // Only calculate array length once

for (let i=0; i<arrayLength; i++) {
  if (!yearsObj[array[i].year]) {
    yearsObj[array[i].year] = [];
  }

  yearsObj[array[i].year].push(array[i]);
}

In this situation, my preference would be to use Array.reduce() . 在这种情况下,我的首选是使用Array.reduce() It is more readable and the performance difference will be negligible. 它更具可读性,并且性能差异可以忽略不计。

const arr = [
  { name: 'greg', year: '2000' },
  { name: 'john', year: '2002' },
  { name: 'bob', year: '2005' },
  { name: 'ned', year: '2000' },
  { name: 'pam', year: '2000' },
];

const result = arr.reduce((prev, curr) => {
  const { year } = curr;
  if (prev[year]) {
    prev[year].push(curr);
  } else {
    prev[year] = [curr];
  }
  return prev;
}, {});

/* Result:
{ '2000': 
   [ { name: 'greg', year: '2000' },
     { name: 'ned', year: '2000' },
     { name: 'pam', year: '2000' } ],
  '2002': [ { name: 'john', year: '2002' } ],
  '2005': [ { name: 'bob', year: '2005' } ] }
*/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM