使用lodash或ramda变换对象数组

时间:2018-07-14 01:27:37

标签: javascript lodash ramda.js

这是查询数据库后获得的数据结构。

[
    { name: 'xx1', date: '2017-09-03', value: 49 },
    { name: 'xx2', date: '2017-10-23', value: 67 },
    { name: 'xx2', date: '2017-12-01', value: 70 },
    ...
]

我想将其转换为:

[
    { name: 'xx1', data: { '2017-09-03': 49 } },
    { name: 'xx2', data: { '2017-10-23': 67, '2017-12-01': 70 } },
    ...
]

该数据结构是使用react-chartkick构建图表所必需的。

有人可以给我建议解决这个问题吗? (尤其是lodash或ramda)

4 个答案:

答案 0 :(得分:2)

我将基于reducefind(ES6)方法使用以下方法:

const data = [
  { name: 'xx1', date: '2017-09-03', value: 49 },
  { name: 'xx2', date: '2017-10-23', value: 67 },
  { name: 'xx2', date: '2017-12-01', value: 70 }
];

const result = data.reduce((acc, item) => {
  const found = acc.find(a => a.name === item.name);
  if (found) {
     found.data[item.date] = item.value;
  } else {
    acc.push({
      name: item.name,
      data: {
        [item.date]: item.value
      }
    });
  }
  return acc;
}, []);

如果您不希望使用ES6,则两种方法都具有lodash版本:reducefind

答案 1 :(得分:2)

您可以使用Array#reduce()累积对象并返回其Object.values()

-is [System.Management.Automation.ErrorRecord]

此方法避免使用时间复杂度为O(n)的const data = [ { name: 'xx1', date: '2017-09-03', value: 49 }, { name: 'xx2', date: '2017-10-23', value: 67 }, { name: 'xx2', date: '2017-12-01', value: 70 } ] const map = data.reduce((acc, { name, date, value }) => { if (!(name in acc)) { acc[name] = { name, data: {} } } acc[name].data[date] = value return acc }, {}) const result = Object.values(map) console.log(result),并使用Array#find()检查存在性和name in acc进行访问,两者均为O(1)时间复杂度,使这种方法总体上为O(n)。

相反,the other answer的总体时间复杂度为O(n 2 )。

答案 2 :(得分:1)

对于使用lodash的解决方案,可以使用其ScrollWindowEx(ptr_hwnd, 0, offset, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0) _.map_.groupBy方法来实现。

我发现使用_.merge样式更容易,但是您可以根据需要轻松地将其转换为一组普通的嵌套调用。

_.chain
const data = [
    { name: 'xx1', date: '2017-09-03', value: 49 },
    { name: 'xx2', date: '2017-10-23', value: 67 },
    { name: 'xx2', date: '2017-12-01', value: 70 },
]

const result = _.chain(data)
  .map(val => ({name: val.name, data: {[val.date]: val.value}})) // convert objects to desired format
  .groupBy("name")                                               // group objects by name
  .map(v => _.merge(...v))                                       // merge objects in each group
  .value();                                                      // done!
  
console.log(result);

答案 3 :(得分:1)

Ramda的R.reduceByR.groupBy可以在这里为您提供帮助。在下面的示例中,R.reduceBy通过其name属性对数组中的对象进行分组,然后通过使用R.assoc建立新对象来组合分组的元素。 R.toPairsR.mapR.zipObj的其余组合将使结果变成您想要的形状。

const fn = R.pipe(
  R.reduceBy((res, {date, value}) => R.assoc(date, value, res), {}, R.prop('name')),
  R.toPairs,
  R.map(R.zipObj(['name', 'data']))
)

const data = [
    { name: 'xx1', date: '2017-09-03', value: 49 },
    { name: 'xx2', date: '2017-10-23', value: 67 },
    { name: 'xx2', date: '2017-12-01', value: 70 }
]

console.log(fn(data))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>