Mr. Benedict
Mr. Benedict

Reputation: 827

Compare IDs in a two-dimensional array with IDs in another two-dimensional array

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

Answers (2)

trincot
trincot

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);

Explanation

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

Nenad Vracar
Nenad Vracar

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

Related Questions