Estoy usando Nodejs y me gustaría agrupar mi matriz de objetos en función de algunos atributos. el ejemplo attr_id & type será único
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" } ];Necesita ser convertido a
[{ "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" } ] } ]Estaba tratando de hacer esto sin ningún paquete como "guión bajo" o "json-agregado". como no hay muchos lugares en el código, hacemos alguna agrupación/agregación
A continuación se muestra cómo pude resolver
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); };Prueba
let tempResult = groupJson(normalizedList,'attr_id');quería saber si hay mejores maneras de hacerlo
Bueno, supongo que puedes hacerlo más dinámico (algo para agrupar por una cantidad desconocida de atributos)
Primero, te doy la respuesta en tu formato de salida en estructura
[{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) Pero, ¿qué sucede si hay un atributo de values que se encuentra en los item originales de la list por la que desea ordenarlos? solo puede existir un valor por clave ... en ese caso, puede cambiar la estructura a
[{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)No estoy necesariamente seguro de si esto es mejor, pero así es como lo haría. Podrías envolver esto fácilmente en una función
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));