Javascript在按属性分组的数组中收集对象值

时间:2019-11-15 07:14:42

标签: javascript arrays

我从API响应中收到以下数组:

[ 
  {group: '1', , value: 'a'}
  {group: '1', , value: 'b'}
  {group: '2', , value: 'c'}
  {group: '2', , value: 'd'}
]  

我想将其转换为以下内容(想要按组顺序接收,可以以任何方式对值进行排序):

[
  {group: '1', values: ['b', 'a'] },
  {group: '2', values: ['c', 'd'] },
]

哪种Javascript函数将是最有效的转换函数?

我可以通过以下方式做到这一点

let result = [];

data.reduce((groupNumber, input) => {
  if (!groupNumber[input.group]) {
     groupNumber[input.group] = {group: input.group, values: []};
     result.push(groupNumber[input.group]);
  }
  groupNumber[input.group].values.push(input);
  return groupNumber;
}, {});

reduce是否在此处使用正确的功能?有没有更有效的方法?

第二,reduce将保留结果中的顺序吗?如果我实际上是首先接收具有组1条目的数据,然后接收具有组2条目的数据,依此类推,那么我可以依靠类似地排序的result吗?

请注意,我只关心组的顺序,而不关心组内的值。

2 个答案:

答案 0 :(得分:0)

我将保留我的答复,因为我们对为什么您的方法很棒有一个很好的解释,因为您有O(N)的计算复杂性(感谢@ CertainPerformance的出色评论),并且您只是迭代数组一次。

测试reduce方法是否保留对象键的顺序:

似乎reduce方法未保留键的顺序。在这里,我们看到键是按顺序排序的,然后依次遍历源数组myArray,但是在Chrome浏览器中,此行为是不可重现的(键已排序):

var myArray = [{letter: 'c'}, {letter:'e'}, {letter: 'e'}, {letter:'b'}, {letter: 'c'}, {letter:'a'}, {letter:'b'}, {letter:'a'}, {letter: 'd'}, {letter: 'd'}, {letter: 'd'}, {letter: 'd'}];
var myOrderedKeys = myArray.reduce((a, {letter}) => {
a[letter] = a[letter] || letter;
a[letter] = letter;

return a;
}, {})

console.log(myOrderedKeys);

另一个例子,我们有多个字母:

let notSimpleLetters = [{letter: 'ce'}, {letter:'ec'}, {letter: 'ec'}, {letter:'bw'}, {letter: 'ce'}, {letter:'aw'}, {letter:'ba'}, {letter:'aa'},
                    {letter: 'df'}, {letter: 'cb'}, {letter: 'dc'}, {letter: 'da'}];
let notSimpleKeys = notSimpleLetters.reduce((a, {letter}) => {
a[letter] = a[letter] || letter;
a[letter] = letter;

return a;
}, {})

console.log(notSimpleKeys);

答案 1 :(得分:0)

实际上,通过使用reduce()或任何其他Array方法,将始终保留顺序,因为它们将从索引0开始执行,直到array的末尾。

但是reduce()主要用于将array元素累积到单个元素中,这不是执行此操作的最佳方法,但也可以使用。

请注意,您使用reduce()的实际代码未返回正确的输出。

我认为Array.map() method在这种情况下更好,但应与Array.filter()结合使用,以删除将与map()一起保存的重复元素:

var result = data.map(v => {
  v.values = data.filter(e => e.group == v.group).map(x => x.value);
  delete v.value;
  return v;
}).filter(x => !x.values.some(e => !e));

演示:

let data = [{
  group: '1',
  value: 'a'
}, {
  group: '1',
  value: 'b'
}, {
  group: '2',
  value: 'c'
}, {
  group: '2',
  value: 'd'
}];


var result = data.map(v => {
  v.values = data.filter(e => e.group == v.group).map(x => x.value);
  delete v.value;
  return v;
}).filter(x => !x.values.some(e => !e));

console.log(result);