简体   繁体   中英

Reduce multi-dimensional array of objects into a single array of object

I have this multi dimensional array of objects -

const initialArray = [
  {
   name: 'aaa', 
   value:[{id:1, data:1}, {id:2, data:2}, {id:3, data:3}]
  },
  {
   name: 'bbb', 
   value:[{id:1, data:4}, {id:2, data:5}, {id:3, data:6}]
  },
  {
   name: 'ccc', 
   value:[{id:1, data:7}, {id:2, data:8}, {id:3, data:7}]
  },
  {
   name: 'ddd', 
   value:[{id:1, data:2}, {id:2, data:1}, {id:3, data:1}]
  }
]

I need to convert it into this array -

const finalArray = [
  {
    id: 1, aaa: 1, bbb: 4, ccc: 7, ddd: 2
  },
  {
    id: 2, aaa: 2, bbb: 5, ccc: 8, ddd: 1
  },
  {
    id: 3, aaa: 3, bbb: 6, ccc: 7, ddd: 1
  }
]

The solution I have right now is

initialArray.reduce((accum, arrayData) => {
  arrayData.value.forEach(element => {
    if (accum.some(el => el.id === element.id)) {
      accum.find(el => el.id === element.id)[arrayData.name] = element.data;
    } else {
        accum.push({ id: element.id, [arrayData.name]: element.data });
    }
  });
  return accum;
}, []);

Is there any better and more elegant way to do this? I'm trying to accomplish this by reducing the number of times I iterate through each array and with lesser code and more readability. As you can see, the some and find during each iteration increases the number of iterations. Is there any way to reduce it?

 function tranform(array) { const obj = {} array.forEach(({name, value}) => (value || []).forEach(({id, data}) => obj[id] = { id, ...obj[id], [name]: data } )) return Object.values(obj) } const initialArray = [ { name: 'aaa', value:[{id:1, data:1}, {id:2, data:2}, {id:3, data:3}] }, { name: 'bbb', value:[{id:1, data:4}, {id:2, data:5}, {id:3, data:6}] }, { name: 'ccc', value:[{id:1, data:7}, {id:2, data:8}, {id:3, data:7}] }, { name: 'ddd', value:[{id:1, data:2}, {id:2, data:1}, {id:3, data:1}] } ] console.log(tranform(initialArray)) 

You could take a Map for collecting objects with same id .

 var initialArray = [{ name: 'aaa', value: [{ id: 1, data: 1 }, { id: 2, data: 2 }, { id: 3, data: 3 }] }, { name: 'bbb', value: [{ id: 1, data: 4 }, { id: 2, data: 5 }, { id: 3, data: 6 }] }, { name: 'ccc', value: [{ id: 1, data: 7 }, { id: 2, data: 8 }, { id: 3, data: 7 }] }, { name: 'ddd', value: [{ id: 1, data: 2 }, { id: 2, data: 1 }, { id: 3, data: 1 }] }], result = Array.from(initialArray .reduce( (m, { name, value }) => value.reduce( (n, { id, data }) => n.set(id, Object.assign( n.get(id) || { id }, { [name]: data } )), m ), new Map ) .values() ); console.log(result); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

Here is what looks readable to me (note that I voted to close your question because "primarily opinion-based"):

 initial = [{ name : "aaa", value : [ { id : 1, data : 1 }, { id : 2, data : 2 }, { id : 3, data : 3 } ] }, { name : "bbb", value : [ { id : 1, data : 4 }, { id : 2, data : 5 }, { id : 3, data : 6 } ] }, { name : "ccc", value : [ { id : 1, data : 7 }, { id : 2, data : 8 }, { id : 3, data : 7 } ] }, { name : "ddd", value : [ { id : 1, data : 2 }, { id : 2, data : 1 }, { id : 3, data : 1 } ] }]; map = {}; final = []; for (i = 0; i < initial.length; i++) { x = initial[i]; for (j = 0; j < x.value.length; j++) { y = x.value[j]; if (!map[y.id]) map[y.id] = { id: y.id }; map[y.id][x.name] = y.data; } } for (k in map) { final.push(map[k]); } for (i = 0; i < final.length; i++) { console.log(JSON.stringify(final[i])); } 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM