Reputation: 139
I'm reciving the next data
[
{ id: "1", name: "test1", rName: "the1" },
{ id: "1", name: "test1", rName: "the2" },
{ id: "1", name: "test1", rName: "the3" },
{ id: "2", name: "test2", rName: "the1" },
{ id: "2", name: "test2", rName: "the2" },
{ id: "3", name: "test3", rName: "the1" }
]
I want to merge it by the id and push the rName's into an array to have this structure
[
{ id: "1", name: "test1", rName: ["the1", "the2","the3"] },
{ id: "2", name: "test2", rName: ["the1", "the2"] },
{ id: "3", name: "test3", rName: ["the1"] }
]
I thought doing it with reduce but didn't succeed, if anyone can point me to the right direction it will be greatly appreciated.
Upvotes: 4
Views: 159
Reputation: 19662
This is a pretty simple case of data reformatting. Code is below.
var data = [
{ id: "1", name: "test1", rName: "the1" },
{ id: "1", name: "test1", rName: "the2" },
{ id: "1", name: "test1", rName: "the3" },
{ id: "2", name: "test2", rName: "the1" },
{ id: "2", name: "test2", rName: "the2" },
{ id: "3", name: "test3", rName: "the1" }
];
var reduced = Object.values(data.reduce(function(accumulator, element) {
if (!accumulator[element.id]) {
accumulator[element.id] = { id: element.id, name: element.name, rName: [] };
}
accumulator[element.id].rName.push(element.rName);
return accumulator;
}, {}));
console.log(reduced);
The accumulator checks if the key by element.id
exists in the accumulator. If it does not, it creates it. It then pushes the new rName
on the existing stack. Object.values()
is then used to make the conversion back to an array.
Upvotes: 2
Reputation: 35222
You can use reduce
and find
like this:
In the reduce accumulator
, check if there is already an item with same id
as the current item being iterated. If yes, push the current item's rName
to the rName
array. Else, push a new item to the accumulator
var data = [
{ id: "1", name: "test1", rName: "the1" },
{ id: "1", name: "test1", rName: "the2" },
{ id: "1", name: "test1", rName: "the3" },
{ id: "2", name: "test2", rName: "the1" },
{ id: "2", name: "test2", rName: "the2" },
{ id: "3", name: "test3", rName: "the1" }
];
const newArray = data.reduce((acc, {id,name,rName}) => {
const existing = acc.find(a => a.id == id);
if (existing)
existing["rName"].push(rName);
else
acc.push({id,name,rName: [rName]})
return acc
}, []);
console.log(newArray)
This is a one line, code-golf answer. (Got the idea from @Sébastien's answer):
var data = [
{ id: "1", name: "test1", rName: "the1" },
{ id: "1", name: "test2", rName: "the2" },
{ id: "1", name: "test2", rName: "the3" },
{ id: "2", name: "test2", rName: "the1" },
{ id: "2", name: "test1", rName: "the2" },
{ id: "3", name: "test3", rName: "the1" }
]
const anotherArray = Object.values(data.reduce((acc, {id,name,rName}) =>
((acc[id] = acc[id] || {id,name,rName:[]})["rName"].push(rName), acc), {}));
console.log(anotherArray)
Upvotes: 1
Reputation: 3
If you adhere to use method 'reduce', you can do like this:
var arr = [
{ id: "1", name: "test1", rName: "the1" },
{ id: "1", name: "test1", rName: "the2" },
{ id: "1", name: "test1", rName: "the3" },
{ id: "2", name: "test2", rName: "the1" },
{ id: "2", name: "test2", rName: "the2" },
{ id: "3", name: "test3", rName: "the1" }
]
var arr1 = arr.reduce(function (a1, a2) {
if (a1 instanceof Array) {
let lastItem = a1[a1.length - 1]
if (lastItem.id == a2.id) {
lastItem.rName.push(a2.rName)
} else {
a1.push({ ...a2, rName: [a2.rName] })
}
return a1
} else {
let result = []
if (a1.id == a2.id) {
result.push({ ...a1, rName: [a1.rName, a2.rName] })
} else {
result.push({ ...a1, rName: [a1, rName] })
result.push({ ...a2, rName: [a2, rName] })
}
return result
}
})
console.log(JSON.stringify(arr1))
But I think you should do like this, for the code is more clear:
var arr = [
{ id: "1", name: "test1", rName: "the1" },
{ id: "1", name: "test1", rName: "the2" },
{ id: "1", name: "test1", rName: "the3" },
{ id: "2", name: "test2", rName: "the1" },
{ id: "2", name: "test2", rName: "the2" },
{ id: "3", name: "test3", rName: "the1" }
]
var map = new Map()
arr.forEach(function(item){
if(map.has(item.id)){
map.get(item.id).rName.push(item.rName)
}else{
map.set(item.id, {...item, rName: [item.rName]})
}
})
var arr1 = Array.from(map.values())
console.log(JSON.stringify(arr1))
Upvotes: 0
Reputation: 1
If each id
can determine a uniquename
, this will work:
let data = [
{ id: "1", name: "test1", rName: "the1" },
{ id: "1", name: "test1", rName: "the2" },
{ id: "1", name: "test1", rName: "the3" },
{ id: "2", name: "test2", rName: "the1" },
{ id: "2", name: "test2", rName: "the2" },
{ id: "3", name: "test3", rName: "the1" }
];
let result = [];
for (let item of data)
{
const index = result.findIndex(i => i.id === item.id);
if (index < 0) {
result.push({ id: item.id, name: item.name, rName: [item.rName] });
}
else {
result[index].rName.push(item.rName);
}
}
Please note this will not work when following data should accept:
[
{ id: "1", name: "test1", rName: "the1" },
{ id: "1", name: "test2", rName: "the2" },
{ id: "1", name: "test2", rName: "the3" },
{ id: "2", name: "test2", rName: "the1" },
{ id: "2", name: "test1", rName: "the2" },
{ id: "3", name: "test3", rName: "the1" }
]
Upvotes: 0
Reputation: 2867
Pure ES6
let result = obj.reduce((acc, item) => {
let found = acc.find(i => i.id === item.id);
found ? (found.rName = [...found.rName, item.rName]) : (acc = [...acc, { ...item, rName: [item.rName] }]);
return acc;
}, []);
Upvotes: 0