Reputation: 23
I am using Nodejs & would like to group my object array based on few attributes.
example attr_id
& type
will be unique
const normalizedList =[ {
"attr_id": 1,
"type": "color",
"value_index": 10,
"value_label": "Blue"
},
{
"attr_id": 1,
"type": "color",
"value_index": 15,
"value_label": "Red"
},
{
"attr_id": 2,
"type": "size",
"value_index": 10,
"value_label": "Small"
},
{
"attr_id": 2,
"type": "size",
"value_index": 14,
"value_label": "Big"
}
];
Needs to be converted to
[{
"attr_id": 1,
"type": "color",
"values": [{
"index": 10,
"label": "Blue"
}, {
"index": 15,
"label": "Red"
}
]
}, {
"attr_id": 2,
"type": "size",
"values": [{
"index": 10,
"label": "Small"
}, {
"index": 14,
"label": "Big"
}
]
}
]
I was trying to do this without any packages like "underscore" or "json-aggregate". as not many places in the code we do any grouping/aggregation
Below is how I was able to solve
const groupJson = (arr,g_label) =>{
// group the list by 'attr_id'
const groupedAttrList = normalizedList.reduce((acc, obj)=>{
let key = obj[g_label]
if (!acc[key]) {
acc[key] = []
}
acc[key].push(obj)
return acc
},{});
const finalArray = [];
// Now iterate over the groupedAttrList
for (let typeRow in groupedAttrList){
let resultObj = {};
let tempRow = groupedAttrList[typeRow];
// as attr_id,type are unique for the set; picking it from 1st
const {attr_id,type} = tempRow [0];
resultObj .attr_id= attr_id;
resultObj .type= type;
// get all the values
resultObj .values = tempRow .map(v=>{
return {index:v.value_index,label:v.value_label};
});
finalArray.push(resultObj );
}
console.log(finalArray);
};
Test
let tempResult = groupJson(normalizedList,'attr_id');
wanted to learn if there are better ways to do it
Upvotes: 0
Views: 219
Reputation: 2189
Im not necessarily sure if this is any better, but this is how I would maybe go about this. You could easily wrap this into a function
const finalObjects = [];
const checkIdInArray = (id) => finalObjects.find((obj) => obj.attr_id === id);
normalizedList.forEach((element) => {
if (!checkIdInArray(element.attr_id)) {
// Then add to array as its not been added yet
finalObjects.push({
attr_id: element.attr_id,
type: element.type,
values: [
{
index: element.value_index,
label: element.value_label,
},
],
});
return;
}
// Get the index of the existing id
const arrIndex = finalObjects.findIndex((e) => e.attr_id === element.attr_id);
finalObjects[arrIndex].values.push({
index: element.value_index,
label: element.value_label,
});
});
console.log(JSON.stringify(finalObjects));
Upvotes: 1
Reputation: 4337
Well I guess you can make it more dynamic(something to group by an unknown amount of attributes)
First, I give you the answer in your output format in structure[{values:[...objectsInGroup],...groupingInfo}, ...otherGroupObjects]
const myList=[{"attr_id":1,"type":"color","value_index":10,"value_label":"Blue"},{"attr_id":1,"type":"color","value_index":15,"value_label":"Red"},{"attr_id":2,"type":"size","value_index":10,"value_label":"Small"},{"attr_id":2,"type":"size","value_index":14,"value_label":"Big"}]
function groupList(list,attributes){
var cache={} //for finding elements that have the same attributes
for(let item of list){
let ID=attributes.map(attr=>item[attr]).join('-')
//items with same ID would be grouped together
cache[ID]? cache[ID].values.push(item): cache[ID]={values:[item]}
//if ID exists.. add to the group, else make the group
attributes.forEach(key=>{
if(!cache[ID][key]){ cache[ID][key]=item[key] }
})
}
return Object.values(cache)
}
const newList=groupList(myList,['attr_id','type'])
console.log(newList)
But what if there was a values
attribute that is in the original item
s in the list
that you wanted it sorted by? only one value can exist per key.. in that case you can change the structure to[{values:[...objectsInGroup],info:{...groupingInfo}} ...otherGroupObjects]
const myList=[{"attr_id":1,"type":"color","value_index":10,"value_label":"Blue"},{"attr_id":1,"type":"color","value_index":15,"value_label":"Red"},{"attr_id":2,"type":"size","value_index":10,"value_label":"Small"},{"attr_id":2,"type":"size","value_index":14,"value_label":"Big"}]
function groupList(list,attributes){
var cache={} //for finding elements that have the same attributes
for(let item of list){
let ID=attributes.map(attr=>item[attr]).join('-')
//items with same ID would be grouped together
cache[ID]? cache[ID].values.push(item): cache[ID]={values:[item]}
//if ID exists.. add to the group, else make the group
if(!cache[ID].info){
cache[ID].info={} //info about the grouping of this array
attributes.forEach(key=>cache[ID].info[key]=item[key])
}
}
return Object.values(cache)
}
const newList=groupList(myList,['attr_id','type'])
console.log(newList)
Upvotes: 2