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

时间:2019-05-09 23:29:55

标签: javascript arrays object

我正在尝试找出最高性能的JavaScript方法,将对象数组转换为具有唯一键的对象和将对象填充为值的数组。

例如:

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

我希望将其转换为:

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

到目前为止,这是我到目前为止所做的:

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]);
}

3 个答案:

答案 0 :(得分:-1)

通过使用数组的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)
);

//输出

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”    }   ]  } }

答案 1 :(得分:-1)

即使Object.fromEntries(array.map(obj => [obj.year,obj]))并不是您真正需要的东西,它也可以这么简单,但是谈论性能却比所有建议的都要慢,因此我举一个糟糕的例子来说明简短声明并非总是最快的。 您的方式似乎是最快的性能。 运行下面的代码片段以查看实际时间。

// 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();

答案 2 :(得分:-2)

for这样的循环(命令式)在大多数情况下可能是最快的。但是,在这种情况下,您不太可能看到很大的不同。可以改善示例中代码的一件事是在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]);
}

在这种情况下,我更喜欢使用Array.reduce()。它更具可读性,并且性能差异可以忽略不计。

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