29
votes

Assume we have the following arrays:

a = [1, 2, 3, 4, 5]

and

b = [2, 3]

How can I subtract b from a? So that we have c = a - b which should be equal to [1, 4, 5]. jQuery solution would also be fine.

6

6 Answers

45
votes

Assuming you're on a browser that has Array.prototype.filter and Array.prototype.indexOf, you could use this:

var c = a.filter(function(item) {
    return b.indexOf(item) === -1;
});

If the browser in question does not have those methods, you may be able to shim them.

8
votes

This is a modified version of the answer posted by @icktoofay.

In ES6 we can make use of:

This will simplify our code to:

var c = a.filter(x => !b.includes(x));

Demo:

var a = [1, 2, 3, 4, 5];
var b = [2, 3];

var c = a.filter(x => !b.includes(x));
console.log(c);
3
votes

For code that would work in all browsers, you would have to manually find each element from b in a and remove it.

var a = [1, 2, 3, 4, 5];
var b = [2, 3];

var result = [], found;
for (var i = 0; i < a.length; i++) {
    found = false;
    // find a[i] in b
    for (var j = 0; j < b.length; j++) {
        if (a[i] == b[j]) {
            found = true;
            break;
        }
    }
    if (!found) {
        result.push(a[i]);
    }
}
// The array result now contains just the items from a that are not in b

Working example here: http://jsfiddle.net/jfriend00/xkBzR/

And, here's a version that could be faster for large arrays because it puts everything into an object for hashed lookups rather than brute force array searching:

var a = [1, 2, 3, 4, 5];
var b = [2, 3];

function filterArray(src, filt) {
    var temp = {}, i, result = [];
    // load contents of filt into object keys for faster lookup
    for (i = 0; i < filt.length; i++) {
        temp[filt[i]] = true;
    }

    // go through src
    for (i = 0; i < src.length; i++) {
        if (!(src[i] in temp)) {
            result.push(src[i]);
        }
    }
    return(result);
}

var filtered = filterArray(a, b);

Working example here: http://jsfiddle.net/jfriend00/LUcx6/

2
votes

For the ones struggling with Objects, like Date, you'll find out that two different objects are never equal to each other, even if they have the same values, so the answers above wouldn't work. Here is an answer to this problem in ES6.

const c = a.filter(aObject => b.findIndex(bObject => aObject.valueOf() === bObject.valueOf()) === -1)
0
votes

Here an implementation for try works in all browsers:

if('filter' in Array == false) {
    Array.prototype.filter = 
        function(callback) {
            if(null == this || void 0 == this) {
                return;
             }
            var filtered = [];
            for(i = 0, len = this.length; i < len; i++) {
                    var tmp = this[i];
                    if(callback(tmp)) {
                        filtered.push(tmp);
                     }
             }
                return filtered;
       }
  }

a = [1, 2, 3, 4, 5]; 
b = [2, 3]; 

var c = a.filter(function(item) { /*implementation of icktoofay */
    return b.indexOf(item) === -1;
});
0
votes

Might be an outdated query but i thought this might be useful to someone.

let first = [1,2,3,4,5,6,7,9];
let second = [2,4,6,8];
const difference = first.filter(item=>!second.includes(item));
console.log(difference);//[ 1, 3, 6,7]
/*
the above will not work for objects with properties
This might do the trick
*/
const firstObj = [{a:1,b:2},{a:3,b:4},{a:5,b:6},{a:7,b:8}]//not ideal. I know
const secondObj = [{a:3,b:4},{a:7,b:8}]

const objDiff = firstObj.filter(obj=>
  !secondObj.find(sec=>//take note of the "!"
    sec.a===obj.a
    &&//or use || if you want to check for either or
    sec.b===obj.b
  )//this is formatted so that it is easily readable
);
console.log(objDiff)/*
[
  {
    "a": 1,
    "b": 2
  },
  {
    "a": 5,
    "b": 6
  }
]
*/