Reputation: 827
Ok, another in the series of grouping Javascript arrays of objects by ID but this time, we have an array of IDs in an object of arrays (item3) which will be compared with another array of objects.
var existingArray = [
{
"item1": "Blah1",
"item2": "blah2",
"item3": ["0200","0300"],
"item4": "blah4",
"item5": "blah5"
},{
"item1": "Blah1",
"item2": "blah2",
"item3": ["0100","0300"],
"item4": "blah4",
"item5": "blah5"
},{
"item1": "Blah1",
"item2": "blah2",
"item3": ["0100"],
"item4": "blah4",
"item5": "blah5"
},{
"item1": "Blah1",
"item2": "blah2",
"item3": ["0300"],
"item4": "blah4",
"item5": "blah5"
},{
"item1": "Blah1",
"item2": "blah2",
"item3": ["0200", "0100"],
"item4": "blah4",
"item5": "blah5"
}
]
Here's our favourite DATA2 array which contains the piece of information we want to pull out (CandidateName) if the "relatedId" is the same as the any of the IDs in item3 in EXISTINGARRAY.
var data2 = [
{"CandidateName": "Mary", "relatedId": ["0100", "0200"]},
{ "CandidateName": "John", "relatedId": ["0200"]},
{ "CandidateName":"Peter", "relatedId": ["0300", "0100"]},
{ "CandidateName": "Paul", "relatedId": ["0300"]}
];
So the idea is if any of the IDs in data2[i].relatedId[j] === existingArray[k].item3[l], pull out the "CandidateName" and add it to the EXISTINGARRAY so we end up with something like the following.
existingArray = [
{
"item1": "Blah1",
"item2": "blah2",
"item3": ["0200","0300"],
"item4": "blah4",
"item5": "blah5",
"item6": ["Mary", "Jonh", "Peter", "Paul"]
},{
"item1": "Blah1",
"item2": "blah2",
"item3": ["0100","0300"],
"item4": "blah4",
"item5": "blah5",
"item6": ["Mary", "Peter", "Paul"]
},{
"item1": "Blah1",
"item2": "blah2",
"item3": ["0100"],
"item4": "blah4",
"item5": "blah5",
"item6": ["Mary", "Peter"]
},{
"item1": "Blah1",
"item2": "blah2",
"item3": ["0300"],
"item4": "blah4",
"item5": "blah5",
"item6": ["Peter", "Paul"]
},{
"item1": "Blah1",
"item2": "blah2",
"item3": ["0200", "0100"],
"item4": "blah4",
"item5": "blah5",
"item6": ["Mary", "John","Peter"]
}
]
Upvotes: 1
Views: 408
Reputation: 350272
Here is an ES6 solution for this:
existingArray.forEach( function (obj) {
obj.item6 = [...new Set(obj.item3.reduce( (acc, id) => acc.concat(this.get(id)), [] ))]
}, data2.reduce (
(acc, obj) => obj.relatedId.reduce (
(acc, id) => acc.set(id, (acc.get(id) || []).concat(obj.CandidateName)), acc
), new Map()
));
var existingArray = [
{
"item1": "Blah1",
"item2": "blah2",
"item3": ["0200","0300"],
"item4": "blah4",
"item5": "blah5"
},{
"item1": "Blah1",
"item2": "blah2",
"item3": ["0100","0300"],
"item4": "blah4",
"item5": "blah5"
},{
"item1": "Blah1",
"item2": "blah2",
"item3": ["0100"],
"item4": "blah4",
"item5": "blah5"
},{
"item1": "Blah1",
"item2": "blah2",
"item3": ["0300"],
"item4": "blah4",
"item5": "blah5"
},{
"item1": "Blah1",
"item2": "blah2",
"item3": ["0200", "0100"],
"item4": "blah4",
"item5": "blah5"
}
]
var data2 = [
{"CandidateName": "Mary", "relatedId": ["0100", "0200"]},
{ "CandidateName": "John", "relatedId": ["0200"]},
{ "CandidateName":"Peter", "relatedId": ["0300", "0100"]},
{ "CandidateName": "Paul", "relatedId": ["0300"]}
];
existingArray.forEach( function (obj) {
obj.item6 = [...new Set(obj.item3.reduce( (acc, id) => acc.concat(this.get(id)), [] ))]
}, data2.reduce (
(acc, obj) => obj.relatedId.reduce (
(acc, id) => acc.set(id, (acc.get(id) || []).concat(obj.CandidateName)), acc
), new Map()
));
console.log(existingArray);
The code really starts at the end, with the creation of an empty Map
:
new Map()
This becomes the variable (named acc
) that accumulates data while data2
is iterated with reduce
:
data2.reduce
This reduce
operation is nested in order to iterate each relatedId
individually. If the accumulated value (acc
) does not yet contain the found id, a new array is created:
acc.get(id) || []
... otherwise the found array value is used. To that the candidate name is appended:
.concat(obj.CandidateName)
... and this is put back into acc
for key id
:
acc.set(id, ...)
As the set
method returns acc
itself, it works very nicely with reduce
which needs this return value in order to pass acc
again to the next call of the callback.
The result of the outer reduce
call is this a Map
that is keyed by all id
values found in data2
, and the value for each is an array of associated names.
This value is then passed as second argument to the forEach
call, and thus becomes the value of this
. So when you see:
this.get(id)
it is retrieving the candidate name array for id
from the Map
described above.
In the forEach
callback another reduce
is made to iterate over the id
values in item3
:
obj.item3.reduce
This accumulates to an array of names which is then passed to the Set
constructor:
new Set(...)
This is done to remove duplicates from the array of names. This Set
is immediately converted to an array again with the spread operator:
[...new Set()]
And so all item6
properties get their value.
Upvotes: 1
Reputation: 122047
You can loop existingArray and add item6 with map()
, and to create that array you can first use filter()
and some()
to filter objects that contain same values in relatedId as current object in existingArray and then just use map()
to return only names and return object.
var existingArray = [{"item1":"Blah1","item2":"blah2","item3":["0200","0300"],"item4":"blah4","item5":"blah5"},{"item1":"Blah1","item2":"blah2","item3":["0100","0300"],"item4":"blah4","item5":"blah5"},{"item1":"Blah1","item2":"blah2","item3":["0100"],"item4":"blah4","item5":"blah5"},{"item1":"Blah1","item2":"blah2","item3":["0300"],"item4":"blah4","item5":"blah5"},{"item1":"Blah1","item2":"blah2","item3":["0200","0100"],"item4":"blah4","item5":"blah5"}];
var data2 = [{"CandidateName":"Mary","relatedId":["0100","0200"]},{"CandidateName":"John","relatedId":["0200"]},{"CandidateName":"Peter","relatedId":["0300","0100"]},{"CandidateName":"Paul","relatedId":["0300"]}];
var result = existingArray.map(function(o) {
o.item6 = data2.filter(function(e) {
return o.item3.some(function(a) {
return e.relatedId.indexOf(a) != -1;
})
}).map(function(e) {
return e.CandidateName;
})
return o;
})
console.log(result)
Upvotes: 1