44

I have two arrays of arrays and am trying to find the difference.

var a = [[ 11, 24, 28, 38, 42, 44 ],
  [ 7, 19, 21, 22, 29, 38 ],
  [ 2, 21, 27, 30, 33, 40 ],
  [ 6, 11, 12, 21, 34, 48 ],
  [ 1, 10, 17, 31, 35, 40 ],
  [ 1, 18, 26, 33, 36, 45 ],
  [ 15, 21, 22, 24, 38, 46 ],
  [ 5, 17, 21, 27, 29, 41 ],
  [ 3, 7, 12, 16, 20, 28 ],
  [ 9, 12, 13, 18, 30, 37 ],
  [ 3, 19, 21, 31, 33, 46 ],
  [ 6, 11, 16, 18, 20, 34 ],
  [ 1, 3, 11, 13, 24, 28 ],
  [ 12, 13, 16, 40, 42, 46 ],
  [ 1, 3, 5, 36, 37, 41 ],
  [ 14, 15, 23, 24, 26, 31 ],
  [ 7, 13, 14, 15, 27, 28 ]];

var b = [[ 4, 7, 9, 21, 31, 36 ],
  [ 2, 5, 6, 12, 15, 21 ],
  [ 4, 7, 8, 15, 38, 41 ],
  [ 11, 24, 28, 38, 42, 44 ],
  [ 7, 19, 21, 22, 29, 38 ]];

How would I find:

c = [[ 2, 21, 27, 30, 33, 40 ],
  [ 6, 11, 12, 21, 34, 48 ],
  [ 1, 10, 17, 31, 35, 40 ],
  [ 1, 18, 26, 33, 36, 45 ],
  [ 15, 21, 22, 24, 38, 46 ],
  [ 5, 17, 21, 27, 29, 41 ],
  [ 3, 7, 12, 16, 20, 28 ],
  [ 9, 12, 13, 18, 30, 37 ],
  [ 3, 19, 21, 31, 33, 46 ],
  [ 6, 11, 16, 18, 20, 34 ],
  [ 1, 3, 11, 13, 24, 28 ],
  [ 12, 13, 16, 40, 42, 46 ],
  [ 1, 3, 5, 36, 37, 41 ],
  [ 14, 15, 23, 24, 26, 31 ],
  [ 7, 13, 14, 15, 27, 28 ]];

I had tried underscore:

_ = require('underscore');
_.difference(a,b);

But it doesn't work.

I also tried lodash:

_ = require('lodash');
_.differenceBy(a,b);

but it doesn't work either.

What am I doing wrong here?

Firdous Alam
  • 563
  • 3
  • 8
  • 16

3 Answers3

72

Use _.differenceWith, and pass a comparator which compares two arrays, as in:

_.differenceWith(a, b, _.isEqual);
alexandre-rousseau
  • 2,321
  • 26
  • 33
  • 4
    I'd like to note that the order of args does matter for `_.differenceBy` and `_.difference`. In the documentation for `_.differenceBy` (lodash), it states: "The order and references of result values are determined by the first array." After some tests I realized the resultant array did not have values from the 2nd array if the 2nd array was longer. The example for `_.difference` in the documentation seems like a poor choice, being `_.difference([2, 1], [2, 3]); // returns [1]`. This has me wondering how you'd get `[1, 3]` if your arrays are eq length, which is what I need. – steezeburger Oct 27 '17 at 02:38
  • 2
    I had the same problem. In that case (for single-level arrays, so avoiding the `With` variants), you can do it by `_.difference(_.union(a, b), _.intersection(a, b))` – dsl101 Nov 03 '17 at 09:29
  • 22
    And I also just discovered `_.xor()`, which I think is much neater :). https://lodash.com/docs/4.17.4#xor – dsl101 Nov 08 '17 at 10:56
  • @StanislavMayorov I just tried using _.xor() in the REPL, and it works on arrays with different lengths. – Max Jul 09 '19 at 02:23
  • @Max yes, it really works. what a surprise. I will delete my comment) – Stanislav Mayorov Jul 09 '19 at 16:04
  • Noticed profound slowness when running this over a large-ish dataset comparing objects. – Sean Halls May 13 '21 at 14:07
  • _.difference(a, b) is different than _.difference(b, a). On different length sets, put the biggest set first. – Carlos Vega May 25 '21 at 15:32
53

As mentioned by @dsl101,

_.xor([1, 2, 3], [2, 3, 4]);
// [1, 4]
KFunk
  • 2,956
  • 22
  • 33
0

If you don't want to use Lodash _.differenceWith, use this naive approach:

function difference(arr1,arr2) {
    let uniqueObj = {}
    let output = []
    for (let i = 0; i < arr1.length; i++) {
        uniqueObj[arr1[i].toString()] = 1
    }
    for (let i = 0; i < arr2.length; i++) {
        uniqueObj[arr2[i].toString()] = 1
    }
    for (let i in uniqueObj) {
        output.push(i.split(',').map(Number))
    }
    return output
}
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574