I am trying to merge JSON objects which have common values.
This is the original JSON:
{
"setA":[
{
"setId":"setA"
,"prodId":"A"
,"price":"5"
,"delivertCost":"1"
,"name":"Set_Prod01"
}
,{
"setId":"setA"
,"prodId":"B"
,"price":"5"
,"delivertCost":"1"
,"name":"Set_Prod01"
}
]
}
Since it has same setId
and name
, I want to make it like this:
{
"setA": {
"setId":"setA"
,"prodId":"A,B"
,"price":"5"
,"deliveryCost":3
,"name":"Set_Prod01"
}
}
To do this, I made this JavaScript code, but it looks terrible and more elements have attributes with if else
than needed.
function groupBy(coll, f) {
return coll.reduce(function(acc, x) {
var k = f(x);
acc[k] = (acc[k] || []).concat(x);
return acc;
}, {});
}
var test = {
items: [{
setId: 'setA', prodId: "A", price: '5', deliveryCost : '1', name: "Set_Prod01"
}, {
setId: 'setA', prodId: "B", price :'5', deliveryCost : '2', name: "Set_Prod01"
}]
};
console.log(JSON.stringify(test));
var result = groupBy(test.items, function(x){return x.setId});
//first grouping
console.log(JSON.stringify(result));
//begin spagetti code... T^T
var secondResult = {};
for(var key in result){
var secondObjForSet = {};
var setGroup = result[key];
for(var i = 0; i < setGroup.length; i++) {
var singleSetItem = setGroup[i];
for(var innerKey in singleSetItem){
if(innerKey == 'deliveryCost'){
secondObjForSet[innerKey] = (typeof secondObjForSet[innerKey] === 'undefined') ? 0 + singleSetItem[innerKey] : (secondObjForSet[innerKey] * 1) + (singleSetItem[innerKey] * 1);
}else if(innerKey == 'prodId'){
secondObjForSet[innerKey] =
(typeof secondObjForSet[innerKey] === 'undefined' || secondObjForSet[innerKey] == '') ?
singleSetItem[innerKey] : secondObjForSet[innerKey] + ',' + singleSetItem[innerKey];
}
else{
secondObjForSet[innerKey] = singleSetItem[innerKey];
}
}
}
secondResult[key] = secondObjForSet;
}
console.log(JSON.stringify(secondResult));
This is not flexible at all, so I need some help to make it more efficient.
1 Answer 1
I am assuming you have the correct target to transform (the input array is filtered).
If you are using es6:
const input = [
{
"setId": "setA",
"prodId": "A",
"price": 5,
"deliveryCost": 1,
"name": "Set_Prod01"
},
{
"setId": "setA",
"prodId": "B",
"price": 5,
"deliveryCost": 2,
"name": "Set_Prod01"
}
];
const output = {
"setId": "setA",
"prodId": "A,B",
"price": 5,
"deliveryCost": 3,
"name": "Set_Prod01"
};
const groupBy = (input) => (
Object.assign(
input[0],
{
prodId: input.map(set => set.prodId).join(','),
deliveryCost: input.map(set => set.deliveryCost).reduce( (cur, next) => cur + next)
}
)
);
console.log(output);
console.log(groupBy(input));
If you are using es6 and stage-2 object spread operator, change the function to:
const groupBy = (input) => (
{
...input[0],
prodId: input.map(set => set.prodId).join(','),
delivertCost: input.map(set => set.deliveryCost).reduce( (cur, next) => cur + next)
}
);
If you are not using es6, simplest method is use it, and use babel to convert it into es5 compatible code. It's less code, more readable and easier to maintain.
EDIT:
The function above simply take an array of objects and assign them into another object. Note that in Object.assign
, the latter's value will overwrite the former's value with the same key, so you can easily implement the overwriting rule you mentioned. The value are simply some functional programming, one join the array of string, and the other sum up the values.
-
\$\begingroup\$ Welcome to Code Review! You have presented an alternative solution, but haven't reviewed the code. Please explain your reasoning (how your solution works and how it improves upon the original) so that the author can learn from your thought process. \$\endgroup\$SuperBiasedMan– SuperBiasedMan2016年04月07日 11:03:40 +00:00Commented Apr 7, 2016 at 11:03
-
\$\begingroup\$ Oops i'm sorry, I updated the reason in the answer above. \$\endgroup\$Kai Hao– Kai Hao2016年04月07日 12:37:18 +00:00Commented Apr 7, 2016 at 12:37
-
\$\begingroup\$ I think it is quite a late, but thanks for your well-formed answer! \$\endgroup\$Juneyoung Oh– Juneyoung Oh2019年05月27日 05:52:56 +00:00Commented May 27, 2019 at 5:52
Explore related questions
See similar questions with these tags.
deliveryCost
3 and not 2 (1 + 1)? How aboutprice
? Why isn't a sum? Not sure I understand what you need... \$\endgroup\$delivery cost
must summed up. andprodId
have to connected with comma, and remain others. The code I provided is working, but I think it is totally not efficient. \$\endgroup\$