Reputation: 125
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?
Upvotes: 2
Views: 1532
Reputation:
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]));
}
Upvotes: 0
Reputation: 867
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))
Upvotes: 5
Reputation: 386550
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; }
Upvotes: 1