Reputation: 1082
say I have a data structure that looks like this:
data = [
{title: "Alpha", content: [{ // 1 item }]},
{title: "Beta", content: [{ // 10 items }]},
{title: "Beta", content: [{ // 12 items }]},
{title: "Beta", content: [{ // 8 items }]}
]
I'd like to figure out a reduce function that would return the following structure:
data = [
{title: "Alpha", content: [{ // 1 item }]},
{title: "Beta", content: [{ // 30 items }]}
]
I've tried looking at some answers where reduce is used based on title but it did not return the new structure with the accumulated content array such as:
data = data.reduce((x, e) => {
x.push(
Object.assign(
{},
e,
messages.find((x) => x.title == e.title)
)
)
return x
}, [])
Any help would be great.
Upvotes: 1
Views: 177
Reputation: 106
I made small changes from @user120242 code.
data = [
{title: "Alpha", content: [{ 1:1 }]},
{title: "Beta", content: [{2:2 }]},
{title: "Beta", content: [{ 3:3}]},
{title: "Beta", content: [{4:4}] }
]
let acc={};
data.forEach((x)=>{
acc[x.title] = acc[x.title] || {title: x.title, content: []}
acc[x.title].content = acc[x.title].content.concat(x.content)
}
)
console.log(acc)
Upvotes: 0
Reputation: 15268
You don't need to use .find
, which has to search the entire array every iteration.
Using reduce and an object map to collect dupes, Object.values to unwrap object to array. spread syntax to feed as push arguments.
data = [
{title: "Alpha", content: [{ 1:1 }]},
{title: "Beta", content: [{2:2 }]},
{title: "Beta", content: [{ 3:3}]},
{title: "Beta", content: [{4:4}] }
]
console.log(
Object.values(data.reduce((acc,{title,content})=>{
acc[title] ?
acc[title].content.push(...content) :
acc[title] = { title, content }
return acc
},{})
))
If IE compatible is needed, there is a polyfill on the above linked documentation. This will also work:
data = [
{title: "Alpha", content: [{ 1:1 }]},
{title: "Beta", content: [{2:2 }]},
{title: "Beta", content: [{ 3:3}]},
{title: "Beta", content: [{4:4}] }
]
function values(obj){
return Object.keys(obj).map(k=>obj[k])
}
console.log(
values(data.reduce((acc,x)=>{
acc[x.title] = acc[x.title] || {title: x.title, content: []}
acc[x.title].content = acc[x.title].content.concat(x.content)
return acc
},{})
))
Upvotes: 2
Reputation: 3966
This might help -
var data = [{
title: "Alpha",
content: [1, 2, 3, 4, 5]
},
{
title: "Beta",
content: [6, 7, 8, 9, 10]
},
{
title: "Beta",
content: [11, 12, 13, 14, 15]
},
{
title: "Beta",
content: [16, 17, 18, 19, 20]
}
]
data = data.reduce((array, item) => {
const existingItem = array.find(innerItem => innerItem.title === item.title);
if (!!existingItem) {
existingItem.content = [...existingItem.content, ...item.content];
} else {
array.push(item);
}
return array;
}, []);
console.log(data);
Upvotes: 2