18

Assume we have the following arrays of objects to be compared based on property id:

a = [{'id':'1', 'name':'a1'}, {'id':'2', 'name':'a2'}, {'id':'3', 'name':'a3'}]

and

b = [[{'id':'2', 'name':'a2'}, ]

How can I subtract b from a? So that we have c = a - b which should be equal to [ {'id':'1', 'name':'a1'}, {'id':'3', 'name':'a3'}].

I have tried using this:

var c= a.filter(function(item) {
                    return !b.includes(item.id);
                });

but still not working.

5
  • 1
    Possible duplicate of What is the fastest or most elegant way to compute a set difference using Javascript arrays? Commented Oct 30, 2017 at 14:31
  • without a filter you can do it in a simple loop where you need to check arrays for the same values: if(a[i].id == b[j].id){ a.splice(i, 1); i-=1; } Commented Oct 30, 2017 at 14:34
  • @Jordumus, in my question I have objects which should be compared based on id attribute. Its not an array of integers or strings as the duplicate question. Commented Oct 30, 2017 at 14:35
  • @AlekseySolovey you woud have a loop nested in another loop in your proposed solution. Commented Oct 30, 2017 at 14:37
  • @Codec which is a valid JavaScript code Commented Oct 30, 2017 at 14:38

4 Answers 4

30

How about this solution? It assumes that 'b' is also an array so for each element of 'a' you check if there is a matching object in 'b'. If there is a matching object then return a false in the filter function so that that element is discarded.

var a = [{
  'id': '1',
  'name': 'a1'
}, {
  'id': '2',
  'name': 'a2'
}, {
  'id': '3',
  'name': 'a3'
}]
var b = [{
  'id': '2',
  'name': 'a2'
}]

var c = a.filter(function(objFromA) {
  return !b.find(function(objFromB) {
    return objFromA.id === objFromB.id
  })
})

console.log(c)

Sign up to request clarification or add additional context in comments.

Comments

19

Here is a nice one line answer :)

Basically, you can filter, as you were trying to do already. Then you can also filter b for each a element and if the length of the filtered b is zero, then you return true because that means the a element is unique to a.

var a = [{
  'id': '1',
  'name': 'a1'
}, {
  'id': '2',
  'name': 'a2'
}, {
  'id': '3',
  'name': 'a3'
}];

var b = [{
  'id': '2',
  'name': 'a2'
}];

c = a.filter( x => !b.filter( y => y.id === x.id).length);
console.log(c);

Comments

12

Easy with new ES6 Syntax

Second and Third way are more performant i guess....

a.filter(i => !b.filter(y => y.id === i.id).length); // One Way
a.filter(i => !b.find(f => f.id === i.id)); // Second Way
a.filter(i => b.findIndex(f => f.id === i.id)) // Third Way

Comments

1

First, you build just a map of the ids you want to delete. Then, you filter your first array with it, like that:

var a = [{
  'id': '1',
  'name': 'a1'
}, {
  'id': '2',
  'name': 'a2'
}, {
  'id': '3',
  'name': 'a3'
}];
var b = [{
  'id': '2',
  'name': 'a2'
}];

var idsToDelete = b.map(function(elt) {return elt.id;});
var result = a.filter(function(elt) {return idsToDelete.indexOf(elt.id) === -1;});
console.log(result)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.