简体   繁体   中英

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.

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

// # 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" } ] } }

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. 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. 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.

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() . 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' } ] }
*/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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