Reputation: 21
I have a JavaScript question that involves combining pieces of different arrays.
I have an array of objects below:
"people": [
{
"city": "SF",
"email": "[email protected]",
"firstName": "Bob",
"id": "1",
"lastName": "Smith"
},
{
"city": "Boston",
"email": "[email protected]",
"firstName": "Bill",
"id": "2",
"lastName": "Anderson"
},
{
"city": "Toronto",
"email": "[email protected]",
"firstName": "Ann",
"id": "3",
"lastName": "Kline",
}
]
I also have an array of tag arrays with an id object in each:
[["tag 1", "tag 2", {"id": "1"}], ["tag 8", "tag 2", {"id": "3"}]]
The expected output would be:
"people": [
{
"city": "SF",
"email": "[email protected]",
"firstName": "Bob",
"id": "1",
"lastName": "Smith",
"tags": ["tag 1", "tag 2"]
},
{
"city": "Boston",
"email": "[email protected]",
"firstName": "Bill",
"id": "2",
"lastName": "Anderson"
},
{
"city": "Toronto",
"email": "[email protected]",
"firstName": "Ann",
"id": "3",
"lastName": "Kline",
"tags": ["tag 8", "tag 2"]
}
]
Is there a way to add the tags to the objects above where the "id"'s match without doing a nested loop. I have tried a couple ways but have failed.
Upvotes: 0
Views: 668
Reputation: 35222
You could create a Map
object which maps each id
with the tags
. Loop through the people array and add a property if the Map has the current id
as key
const people=[{city:"SF",email:"[email protected]",firstName:"Bob",id:"1",lastName:"Smith"},{city:"Boston",email:"[email protected]",firstName:"Bill",id:"2",lastName:"Anderson"},{city:"Toronto",email:"[email protected]",firstName:"Ann",id:"3",lastName:"Kline",}],
tags = [["tag 1", "tag 2", {"id": "1"}], ["tag 8", "tag 2", {"id": "3"}]]
const map = new Map( tags.map(t => [t.pop().id, t]) )
for (const p of people)
if (map.has(p.id))
p.tags = map.get(p.id)
console.log(people)
You can also create a version which doesn't mutate the arrays
const map = new Map;
for (const t of tags)
map.set( t[t.length - 1].id, t.slice(0, -1) )
const output = people.map(p => ({
...p,
tags: map.get(p.id) ?? []
}));
Upvotes: 1
Reputation: 12909
Maybe something like this:
let input = [
{
"city": "SF",
"email": "[email protected]",
"firstName": "Bob",
"id": "1",
"lastName": "Smith"
},
{
"city": "Boston",
"email": "[email protected]",
"firstName": "Bill",
"id": "2",
"lastName": "Anderson"
},
{
"city": "Toronto",
"email": "[email protected]",
"firstName": "Ann",
"id": "3",
"lastName": "Kline",
}
]
let toAdd = [["tag 1", "tag 2", {"id": "1"}], ["tag 8", "tag 2", {"id": "3"}]].reduce((acc, el) => {
// build a object with id -> list of tags
acc[el.find(o => typeof o === 'object' && o !== null).id] = el.filter(o => !(typeof o === 'object' && o !== null))
return acc;
}, {})
console.log(input.map(el => {
// add the tags to el if tags exists
el.tags = toAdd[el.id] || [];
return el
}))
this is O(n^2)
.. if you are certain that your array has always that object at the end, you can have a O(n)
with
let input = [
{
"city": "SF",
"email": "[email protected]",
"firstName": "Bob",
"id": "1",
"lastName": "Smith"
},
{
"city": "Boston",
"email": "[email protected]",
"firstName": "Bill",
"id": "2",
"lastName": "Anderson"
},
{
"city": "Toronto",
"email": "[email protected]",
"firstName": "Ann",
"id": "3",
"lastName": "Kline",
}
]
let toAdd = [["tag 1", "tag 2", {"id": "1"}], ["tag 8", "tag 2", {"id": "3"}]].reduce((acc, el) => {
// build a object with id -> list of tags
acc[el.pop().id] = el
return acc;
}, {})
console.log(input.map(el => {
// add the tags to el if tags exists
el.tags = toAdd[el.id] || [];
return el
}))
Upvotes: 0