[英]Transform array of objects using lodash or ramda
This is the data structure that I got after doing query database. 这是查询数据库后获得的数据结构。
[
{ name: 'xx1', date: '2017-09-03', value: 49 },
{ name: 'xx2', date: '2017-10-23', value: 67 },
{ name: 'xx2', date: '2017-12-01', value: 70 },
...
]
I want to transform it into: 我想将其转换为:
[
{ name: 'xx1', data: { '2017-09-03': 49 } },
{ name: 'xx2', data: { '2017-10-23': 67, '2017-12-01': 70 } },
...
]
That data structure is needed in order to build chart using react-chartkick . 为了使用react-chartkick构建图表,需要该数据结构。
Can anyone give me suggestion to solve this? 谁能给我建议解决这个问题? (Especially with lodash or ramda)
(尤其是lodash或ramda)
I would use following approach based on reduce
and find
(ES6) methods: 我将基于
reduce
和find
(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;
}, []);
If you don't want ES6, both methods have lodash
versions: reduce , find . 如果您不希望使用ES6,则这两种方法都具有
lodash
版本: reduce , find 。
You can accumulate an object with Array#reduce()
and return its Object.values()
: 您可以使用
Array#reduce()
累积对象并返回其Object.values()
:
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)
This approach avoids using Array#find()
which is O(n) time complexity and uses name in acc
to check for existence and acc[name]
for access, which are both O(1) time complexity, making this approach O(n) overall. 这种方法避免使用
Array#find()
,它的时间复杂度为O(n),并且name in acc
使用name in acc
来检查是否存在,并且使用acc[name]
进行访问,这两者都是O(1)的时间复杂度,因此该方法为O(n ) 总体。
In contrast, the other answer is O(n 2 ) time complexity overall. 相反, 另一个答案是总体的O(n 2 )时间复杂度。
For a solution using lodash, you can use its _.map
, _.groupBy
, and _.merge
methods to accomplish this. 对于使用lodash的解决方案,可以使用其
_.map
, _.groupBy
和_.merge
方法来完成此任务。
I find it's easier to follow using the _.chain
style, but you can easily convert it to a normal set of nested calls if you like. 我发现使用
_.chain
样式更容易_.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);
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.10/lodash.min.js"></script>
Ramda's R.reduceBy
or R.groupBy
can help you here. R.reduceBy
的R.reduceBy
或R.groupBy
可以在这里为您提供帮助。 In the example below R.reduceBy
groups the objects in the array by their name
property and then combines the grouped elements by building up the new object with R.assoc
. 在下面的示例中,
R.reduceBy
通过name
属性对数组中的对象进行分组,然后通过使用R.assoc
建立新对象来组合分组的元素。 The remaining combination of R.toPairs
, R.map
and R.zipObj
will get the result into the shape you want. R.toPairs
, R.map
和R.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>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.