1314

Is there a way to return the difference between two arrays in JavaScript?

For example:

var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];

// need ["c", "d"]
halfer
  • 19,824
  • 17
  • 99
  • 186
John Adawan
  • 13,329
  • 4
  • 20
  • 11
  • 16
    Symmetric or non-symmetric? – Lightness Races in Orbit Jan 30 '14 at 18:20
  • 2
    With new ES6 function this can be done as a simple one liner (it will take a lot of time to be able to use in all major browsers). In any case check my [answer](http://stackoverflow.com/a/27997169/1090562) – Salvador Dali Jan 17 '15 at 07:16
  • 2
    an important aspect of the solution is performance. the asymptotic time complexity of this type of operation - in other languages - is `O(a1.length x log(a2.length))` - is this performance possible in JavaScript? – Raul Jun 10 '17 at 17:14
  • Check my library, it can help you with this, @netilon/differify is one of the fastest diff libraries for object/array comparison: https://www.npmjs.com/package/@netilon/differify – Fabian Orue Jul 09 '20 at 18:51
  • 1
    1. Convert a1 into a set. o(a1). 2. Iterate over e2 to see what it has that e1 does not. o(e2). 3. Push the diff into another array then return it after step 2 is finished. – powerup7 Jan 08 '22 at 02:36
  • you can use fitler, check my answer https://stackoverflow.com/a/74317431/14560009 – Manu Rastogi Nov 04 '22 at 13:09

84 Answers84

2846

There is a better way using ES7:


Intersection

 let intersection = arr1.filter(x => arr2.includes(x));

Intersection difference Venn Diagram

For [1,2,3] [2,3] it will yield [2,3]. On the other hand, for [1,2,3] [2,3,5] will return the same thing.


Difference

let difference = arr1.filter(x => !arr2.includes(x));

Right difference Venn Diagram

For [1,2,3] [2,3] it will yield [1]. On the other hand, for [1,2,3] [2,3,5] will return the same thing.


For a symmetric difference, you can do:

let difference = arr1
                 .filter(x => !arr2.includes(x))
                 .concat(arr2.filter(x => !arr1.includes(x)));

Symmetric difference Venn Diagram

This way, you will get an array containing all the elements of arr1 that are not in arr2 and vice-versa

As @Joshaven Potter pointed out on his answer, you can add this to Array.prototype so it can be used like this:

Array.prototype.diff = function(arr2) { return this.filter(x => !arr2.includes(x)); }
[1, 2, 3].diff([2, 3])
user229044
  • 232,980
  • 40
  • 330
  • 338
Luis Sieira
  • 29,926
  • 3
  • 31
  • 53
  • 11
    Computing the `Array` difference is a so called `set operation`, because property lookup is the very own job of `Set`s, which are orders of magnitude faster then `indexOf`/`includes`. Simply put, your solution is very inefficient and rather slow. –  Oct 18 '16 at 19:35
  • 2
    @ftor but with `Set`, values have to be unique, no? – CervEd Oct 23 '16 at 14:20
  • @CervEd Actually, ftor is right. Difference is a concept that doesn't really make sense in arrays. My solution will remove from array A all the occurrences of the elements appearing only once in array B. On the other hand, for most use cases, like the one presented by the OP, it is a good approach. Considering that the code will most likely be run by a browser, efficiency is not a problem because big arrays would not have been sent to the front-end in the first place. If the repetition should be considered, this solution will not work. I'll update my answer at some point in the near future. – Luis Sieira Oct 24 '16 at 09:26
  • 3
    @LuisSieira I get that it would work for `[1,2,3] [2,3,5]` given that the numbers are unique but if you had say `[1,1,2,3] [1,2,3,5]` and expected `[1]` you couldn't use `Set`. Your solution wouldn't work either though :-/ I ended up creating [this function](http://pastebin.com/ceVJ92uz) because I couldn't figure out a satisfactory way to do it more succinctly. If you have any ideas on how to do that, I'd love to know! – CervEd Oct 24 '16 at 10:31
  • Fantastic explanation! It reminds me of Jeff Atwood's SQL join post: https://blog.codinghorror.com/a-visual-explanation-of-sql-joins/ – bkidd Mar 29 '18 at 14:47
  • 9
    Isn't `Array.includes()` ES7 feature instead of ES6? [(1)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes) [(2)](https://www.ecma-international.org/ecma-262/7.0/#sec-array.prototype.includes) — and to continue, with ES6 you could use `Array.some()` e.g. `let intersection = aArray.filter(a => bArray.some(b => a === b))`, no? – Jari Keinänen May 24 '18 at 08:18
  • I'm confused by what arr1 and arr2 are in your examples. I don't see them defined. `Array.prototype.diff = arr1.filter(x => arr2.includes(x)); ^ ReferenceError: arr1 is not defined` – chovy Sep 20 '18 at 06:03
  • 1
    @chovy arr1 and arr2 are the arrays you're performing the operation with. – Luis Sieira Sep 20 '18 at 09:30
  • @LuisSieira yes, `arr1` and `arr2` are the arrays you perform the operations on but it doesn't make sense to assign *the result* of the filter operation to a property on the array prototype. `Array.prototype.diff = arr1.filter(x => arr2.includes(x));` should probably be something like `Array.prototype.diff = function(otherArr) { return this.filter(x => otherArr.includes(x)) };` so you can *then* do `[1, 2, 3].diff([2, 3])`. Although adding to the prototype is probably as bad idea as always. – VLAZ Oct 29 '19 at 17:31
  • Only if you are looking for the same object, not equal objects. You will need to use filter and a custom function for that, otherwise a = {a: 1}; b = {a: 1}; c = [a, {a:1}]; c includes a, but does not include b – Luis Sieira Mar 25 '20 at 12:40
  • great answer, but should rename variables arr1/arr2 to arrA/arrB to match the diagrams – pstanton Oct 04 '21 at 06:43
  • 1
    does not work here [4,9,5] [9,4,9,8,4] – rashi jain Jan 05 '22 at 13:10
  • 1
    @rashijain, As some comments state, "difference" is not a thing in arrays, it is a set operation. My examples do the equivalent of that in arrays. For what I think you want to do, remove a single copy of the elements, you need something like this ```arr2_copy = [...arr2]; arr1.filter((elem) => { if (arr2_copy.includes(elem)) { arr2_copy.pop(elem); return false; } else { return true; }});``` – Luis Sieira Jan 10 '22 at 09:41
  • This answer should be pinned to the homepage as a guideline as for how to write an answer on StackExchange network – noamyg Jul 25 '22 at 09:18
  • 1
    See also [Nina Scholz's answer](https://stackoverflow.com/a/49094302/15261914). I tried using a binary search instead of `includes`, which obviously gave massive speed increases (improved the complexity from `O(n^2)` to `O(n log2 n)`). Using her little function instead of binary search came out 2-3x times faster, especially when the arrays were almost the same. 10x+ when using crazy arrays (100,000,000 elements)... – Darryl Noakes Aug 23 '22 at 15:02
  • https://jsbench.me/oal76coxx0/2 – Darryl Noakes Aug 23 '22 at 15:42
  • This answer worked the best for me after trying all solutions on this question, and I also looked at Nina Scholz's answer. It returns correctly whether there are more or fewer items in arr1 vs arr2. I needed the diff code to tell me if there is a mismatch between the arrays in either direction. On performance: KIMT it could very well be 'slower' than other solutions posted because it is successfully checking for diffs in both directions. If you don't need to do that, then obviously this wouldn't be the right solution for you. Thanks for sharing it, Luis! – Kreidol Oct 13 '22 at 19:35
  • What should I modify to make it for many arrays? – Menai Ala Eddine - Aladdin Feb 14 '23 at 22:24
957

Array.prototype.diff = function(a) {
    return this.filter(function(i) {return a.indexOf(i) < 0;});
};

//////////////
// Examples //
//////////////

const dif1 = [1,2,3,4,5,6].diff( [3,4,5] );  
console.log(dif1); // => [1, 2, 6]


const dif2 = ["test1", "test2","test3","test4","test5","test6"].diff(["test1","test2","test3","test4"]);  
console.log(dif2); // => ["test5", "test6"]

Note .indexOf() and .filter() are not available before IE9.

double-beep
  • 5,031
  • 17
  • 33
  • 41
Joshaven Potter
  • 10,308
  • 2
  • 18
  • 8
  • 1
    Also, you may find useful [editing tutorial](http://stackoverflow.com/editing-help) – Nikita Rybak Oct 26 '10 at 20:09
  • 55
    The only browser that matters that doesn't support filter and indexOf is IE8. IE9 does support them both. So it's not wrong. – Bryan Larsen May 22 '11 at 17:37
  • 16
    ie7 and ie8 are still (unfortunately) very relevant, however you can find polyfill code for both functions on the MDN site: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf Load in the code listed under "compatability" via an IE conditional & BOOM. Ie7/8 are supported. – 1nfiniti May 23 '12 at 19:22
  • 2
    you could also use the filter function provided by jQuery. – Mortimer Jun 08 '12 at 12:48
  • 49
    This solution has a run time of O(n^2) a linear solution would be far more efficient. – jholloman Sep 06 '12 at 18:43
  • 79
    If you use the function like this: `[1,2,3].diff([3,4,5])` it will return `[1,2]` instead of `[1,2,4,5]` so it doesn't solve the problem in the original question, something to be aware of. – Bugster Nov 14 '12 at 17:50
  • 2
    Beware, this implementation will not work for arrays of objects. See http://stackoverflow.com/q/8672383/14731 for more information. – Gili Dec 31 '12 at 19:51
  • 14
    @AlinPurcaru Not supported by archaic browsers != wrong. Considering Netscape 2.0, most of the JS code here is "wrong" by this definition. It's a silly thing to say. – NullUserException Jan 12 '13 at 00:47
  • 1
    @Bugster Good point. It seems like the original poster was asking for the symmetric difference. – Tim Seguine Feb 22 '13 at 14:07
  • Netscape 2.0 isn't 5.8% of the browser market. I'd be scarce to call that browser "archaic", and I think the footnote to this answer is extremely relevant as it gives an answer that will cause a large number of users to hit an error. The answer should be corrected by referencing the polyfill from the note by @mikeyUX above. (-1) – hayesgm Mar 11 '13 at 05:53
  • 1
    Note: this doesn't return the same results if you flip the arrays. – Paul Stanley May 17 '13 at 14:12
  • 3
    @jholloman : a O(n*log(n)) solution would be to sort the 2 arrays and then do a linear merge. Can we better that ? – sbr Jul 18 '13 at 01:14
  • 4
    @jholloman: yes indeed, and an O(1) would indeed be even more efficient! – csabahenk Sep 18 '13 at 23:56
  • 8
    For me the biggest downside of this is that it modifies the prototype of a built-in object. I prefer to avoid that. – Stijn de Witt Sep 02 '15 at 08:19
  • 2
    This only finds what the left array _has_ that the right array _does not_, but not vice versa. Therefore, if you call `[1,2,3,4,5,6].diff( [3,4,5,10] );`, your result will be `[1, 2, 6]`, rather than the expected `[1, 2, 6, 10]`. – Michael Plautz May 10 '16 at 19:06
  • 1
    @StijndeWitt If u dont like prototype... just use it as a function or in-line and not add as prototype? – Andrew Jun 02 '17 at 15:16
  • @Andrew as a regular function, it would be like this? `function diff(a, firstArray) { return firstArray.filter(function(i) {return a.indexOf(i) < 0;}); };` so to use it, `diff([3,4,5], [1,2,3,4,5,6]) // [1,2,3,6]` – Rivo Aug 02 '19 at 06:32
  • While only an example, I would *strongly recommend against* the use of monkey-patching anything due to stuff like this: https://developers.google.com/web/updates/2018/03/smooshgate. Nobody wants a second "smooshgate" I'm sure :) – SidOfc Aug 08 '19 at 13:10
  • Amazing. On `ruby` code, the *Array.diff* is builtin: `array1 - array2`. – Victor May 16 '21 at 06:47
  • @MichaelPlautz that depends on how you define the `diff`. What you propose can be achieved like this: [...arr1.diff(arr2), ...arr2.diff(arr1)] – vir us Aug 18 '23 at 11:44
371

This answer was written in 2009, so it is a bit outdated, also it's rather educational for understanding the problem. Best solution I'd use today would be

let difference = arr1.filter(x => !arr2.includes(x));

(credits to other author here)

I assume you are comparing a normal array. If not, you need to change the for loop to a for .. in loop.

function arr_diff (a1, a2) {

    var a = [], diff = [];

    for (var i = 0; i < a1.length; i++) {
        a[a1[i]] = true;
    }

    for (var i = 0; i < a2.length; i++) {
        if (a[a2[i]]) {
            delete a[a2[i]];
        } else {
            a[a2[i]] = true;
        }
    }

    for (var k in a) {
        diff.push(k);
    }

    return diff;
}

console.log(arr_diff(['a', 'b'], ['a', 'b', 'c', 'd']));
console.log(arr_diff("abcd", "abcde"));
console.log(arr_diff("zxc", "zxc"));
Thinker
  • 14,234
  • 9
  • 40
  • 55
  • 67
    This may work but it does three loops to accomplish what can be done in one line of code using the filter method of Array. – Joshaven Potter Oct 26 '10 at 18:37
  • 13
    Just to be clear, this implements the _symmetric difference_ of _a1_ and _a2_, unlike the other answers posted here. – 200_success Dec 13 '13 at 01:19
  • This is still relevant if you have to support IE8, which does not have filter – Mike Demenok Jun 04 '14 at 08:30
  • Downvote as well. If we promote bad practice and ancient browser support, then where are we heading? Hey, let's go back to a waterfall project management, it's not wrong, is it? – Teodor Sandu Oct 10 '14 at 07:16
  • 36
    This isn't the best answer, but I'm giving it a charity upvote, to help make up for the unfair downvotes. Only *wrong* answers ought to be downvoted, and if I was working on a project with cruft-browsers in scope (tough times happen), this answer might even be helpful. – Michael Scheper Jan 14 '15 at 03:34
  • 3
    May I know what will happen when `var a1 = ['a', 'b'];` and `var a2 = ['a', 'b', 'c', 'd', 'b'];`, **it will return wrong answer**, i.e. `['c', 'd', 'b']` instead of `['c', 'd']`. – skbly7 Oct 11 '15 at 23:38
  • I ran this into an online compiler. This converts numbers in arrays to strings when it returns them. –  Nov 29 '15 at 05:57
  • 1
    This part: 'for (var k in a) {' converts objects in your array to strings or numbers, so I am downvoting. I don't think this answer deserves 51 votes. Sorry. – user1158559 Nov 30 '15 at 11:09
  • 5
    The fastest way is the most obviously naive solution. I tested all of the proposed solutions for symmetric diff in this thread, and the winner is: `function diff2(a, b) { var i, la = a.length, lb = b.length, res = []; if (!la) return b; else if (!lb) return a; for (i = 0; i < la; i++) { if (b.indexOf(a[i]) === -1) res.push(a[i]); } for (i = 0; i < lb; i++) { if (a.indexOf(b[i]) === -1) res.push(b[i]); } return res; }` – nomæd Feb 27 '16 at 13:23
  • User @JoLiss had an almost identical solution, by the way. – nomæd Feb 27 '16 at 13:33
  • Solution in post not works when we have null values in array ex a=[22,33,null,null], b=[22,33] result r should be r=[null,null]. @Nomaed solution in his above comment works. – Kamil Kiełczewski Dec 30 '16 at 23:07
  • This is not normal difference but symmetric difference - or UNION MINUS INTERSECTION. To make it a regular difference, remove the lines: } else { a[a2[i]] = true; in the mid for-loop. – olekeh Mar 08 '17 at 21:42
  • @JoshavenPotter - yes its true but filter is extremely slow when you are dealing with large arrays. Try arrays with 10000 or 100000 items in it. Filter performance is really bad in that kind of scenario which is sad. – born2fr4g Jan 06 '19 at 10:27
  • 1
    Yeah man, this is the year 2020. You should update the answer with the modern approach: filter and includes. – Daniel Viglione Apr 03 '20 at 22:14
  • pHp has this in the standard library :-) – Peter Chaula Jul 07 '20 at 13:54
  • Well there are some errorneous claims about the algorithm speed. Check out my answer comparing all three methods with jsPerf. – Lukáš Řádek Jul 12 '20 at 12:00
  • the function arr_diff loop is the best performance. Comparing 2 arrays 180k each of very long filenames found 200 differences, took this function instantly, compared to the 1 liner filter method took 1min. – Nhon Ha Jul 10 '23 at 12:03
312

This is by far the easiest way to get exactly the result you are looking for, using jQuery:

var diff = $(old_array).not(new_array).get();

diff now contains what was in old_array that is not in new_array

mahemoff
  • 44,526
  • 36
  • 160
  • 222
superphonic
  • 7,954
  • 6
  • 30
  • 63
  • 4
    @Batman Yes, but only if they are references to the _same_ object (`{a: 1} != {a: 1}`) ([proof](http://jsfiddle.net/degq74y0/)) – Matteo B. Sep 15 '14 at 16:31
  • Is it possible to use it with arrays holding data of a custom object? I tried it actually the same way but it didn't worked. Any ideas will be highly appreciable. – LetMeCodeYou Jan 30 '15 at 03:32
  • 10
    Is this a trick? The [doc](http://api.jquery.com/get/) considers this method as part of the [DOM Element Methods](http://api.jquery.com/category/miscellaneous/dom-element-methods/) and not as a general array helper. So it might work this way now, but maybe not in future versions, as it wasn't intended to use it in this way. Although, I'd be happy if it would officially be a general array helper. – robsch Apr 30 '15 at 11:27
  • 2
    @robsch When you use `.not` with an array, jQuery uses it's built-in utility `.grep()` which is specifically for filtering arrays. I can't see this changing. – superphonic Oct 05 '15 at 09:15
  • Any chance to adapt this for Angular2 / typescript? – SoS Dec 20 '16 at 14:41
  • you have to make sure `old_array` is the one which has more values than `new_array`, else, it won't return the diff... which sucks. – vsync Jan 28 '17 at 22:16
  • 1
    @vsync Sounds like you are after a symmetric difference – superphonic Jan 30 '17 at 10:21
  • I don't know, I didn't study computer science. I know I'm after getting the diff of 2 arrays, is all – vsync Jan 30 '17 at 13:16
  • what's the time complexity of this? is it `O(m x n)`, where `m` is the length of `old_array` ad `n` the length of `new_array`? – Raul Jun 10 '17 at 17:11
  • For ExtJS use [`Ext.Array.difference(array1, array2)`](http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.Array-method-difference). – MarthyM Nov 21 '17 at 11:08
177

The difference method in Underscore (or its drop-in replacement, Lo-Dash) can do this too:

(R)eturns the values from array that are not present in the other arrays

_.difference([1, 2, 3, 4, 5], [5, 2, 10]);
=> [1, 3, 4]

As with any Underscore function, you could also use it in a more object-oriented style:

_([1, 2, 3, 4, 5]).difference([5, 2, 10]);
nickf
  • 537,072
  • 198
  • 649
  • 721
mahemoff
  • 44,526
  • 36
  • 160
  • 222
  • 4
    I think it's a good solution performance-wise, especially as lodash and underscore keep battling for the best implementation. Also, it's IE6-compatible. – mahemoff Sep 07 '12 at 18:44
  • 4
    Beware, this implementation will not work for arrays of objects. See http://stackoverflow.com/q/8672383/14731 for more information. – Gili Dec 31 '12 at 19:52
  • 1
    As one of the answers mentions there, it works if it's the same object, but not if two objects have the same properties. I think that's okay as notions of equality vary (e.g. it could also be an "id" attribute in some apps). However, it would be good if you could pass in a comparison test to intersect(). – mahemoff Jan 01 '13 at 02:12
  • For posterity: Lodash now has _.differenceBy() which takes a callback to do the comparison; if you're comparing objects you can drop in a function that compares them however you need. – SomeCallMeTim Sep 08 '16 at 21:13
  • 3
    Be careful if the order of arguments reversed, it will not work. eg. _.difference( [5, 2, 10], [1, 2, 3, 4, 5]); can not get the diff – Russj Oct 04 '16 at 15:32
  • Order always matters when calculating difference of 2 collections ... it's a question of which side of the venn diagram you want. – mahemoff Oct 04 '16 at 16:41
98

Plain JavaScript

There are two possible intepretations for "difference". I'll let you choose which one you want. Say you have:

var a1 = ['a', 'b'     ];
var a2 = [     'b', 'c'];
  1. If you want to get ['a'], use this function:

    function difference(a1, a2) {
      var result = [];
      for (var i = 0; i < a1.length; i++) {
        if (a2.indexOf(a1[i]) === -1) {
          result.push(a1[i]);
        }
      }
      return result;
    }
    
  2. If you want to get ['a', 'c'] (all elements contained in either a1 or a2, but not both -- the so-called symmetric difference), use this function:

    function symmetricDifference(a1, a2) {
      var result = [];
      for (var i = 0; i < a1.length; i++) {
        if (a2.indexOf(a1[i]) === -1) {
          result.push(a1[i]);
        }
      }
      for (i = 0; i < a2.length; i++) {
        if (a1.indexOf(a2[i]) === -1) {
          result.push(a2[i]);
        }
      }
      return result;
    }
    

Lodash / Underscore

If you are using lodash, you can use _.difference(a1, a2) (case 1 above) or _.xor(a1, a2) (case 2).

If you are using Underscore.js, you can use the _.difference(a1, a2) function for case 1.

ES6 Set, for very large arrays

The code above works on all browsers. However, for large arrays of more than about 10,000 items, it becomes quite slow, because it has O(n²) complexity. On many modern browsers, we can take advantage of the ES6 Set object to speed things up. Lodash automatically uses Set when it's available. If you are not using lodash, use the following implementation, inspired by Axel Rauschmayer's blog post:

function difference(a1, a2) {
  var a2Set = new Set(a2);
  return a1.filter(function(x) { return !a2Set.has(x); });
}

function symmetricDifference(a1, a2) {
  return difference(a1, a2).concat(difference(a2, a1));
}

Notes

The behavior for all examples may be surprising or non-obvious if you care about -0, +0, NaN or sparse arrays. (For most uses, this doesn't matter.)

Jo Liss
  • 30,333
  • 19
  • 121
  • 170
  • 3
    Thank. you saved my day. I had to compare a 300K arrays, and your "Set" solution worked perfectly. This should be the accepted answer. – justadev Jan 08 '20 at 10:28
  • The fact that I had to scroll all the way down to this answer before someone detailed using a `Set` to solve this problem is amazing. – Aaron Beaudoin Dec 28 '21 at 14:59
75

A cleaner approach in ES6 is the following solution.

var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];

Difference

a2.filter(d => !a1.includes(d)) // gives ["c", "d"]

Intersection

a2.filter(d => a1.includes(d)) // gives ["a", "b"]

Disjunctive Union (Symmetric Difference)

[ ...a2.filter(d => !a1.includes(d)),
  ...a1.filter(d => !a2.includes(d)) ]
ifelse.codes
  • 2,289
  • 23
  • 21
  • It works only in one direction. Now imagine that `a1 = ['a', 'b', 'e']` : **e** won't be extracted. – imrok Feb 06 '20 at 08:13
  • yes, that's how the difference in set theory works. (a2 -a1) what you are looking for is (a2-a1) + (a1-a2) – ifelse.codes Feb 06 '20 at 09:38
  • 2
    @imrok I believe this is what you are looking for [...a2.filter(d => !a1.includes(d)) , ...(a1.filter(d => !a2.includes(d)))] – ifelse.codes Feb 06 '20 at 16:31
69

To get the symmetric difference you need to compare the arrays in both ways (or in all the ways in case of multiple arrays)

enter image description here


ES7 (ECMAScript 2016)

// diff between just two arrays:
function arrayDiff(a, b) {
    return [
        ...a.filter(x => !b.includes(x)),
        ...b.filter(x => !a.includes(x))
    ];
}

// diff between multiple arrays:
function arrayDiff(...arrays) {
    return [].concat(...arrays.map( (arr, i) => {
        const others = arrays.slice(0);
        others.splice(i, 1);
        const unique = [...new Set([].concat(...others))];
        return arr.filter(x => !unique.includes(x));
    }));
}

ES6 (ECMAScript 2015)

// diff between just two arrays:
function arrayDiff(a, b) {
    return [
        ...a.filter(x => b.indexOf(x) === -1),
        ...b.filter(x => a.indexOf(x) === -1)
    ];
}

// diff between multiple arrays:
function arrayDiff(...arrays) {
    return [].concat(...arrays.map( (arr, i) => {
        const others = arrays.slice(0);
        others.splice(i, 1);
        const unique = [...new Set([].concat(...others))];
        return arr.filter(x => unique.indexOf(x) === -1);
    }));
}

ES5 (ECMAScript 5.1)

// diff between just two arrays:
function arrayDiff(a, b) {
    var arrays = Array.prototype.slice.call(arguments);
    var diff = [];

    arrays.forEach(function(arr, i) {
        var other = i === 1 ? a : b;
        arr.forEach(function(x) {
            if (other.indexOf(x) === -1) {
                diff.push(x);
            }
        });
    })

    return diff;
}

// diff between multiple arrays:
function arrayDiff() {
    var arrays = Array.prototype.slice.call(arguments);
    var diff = [];

    arrays.forEach(function(arr, i) {
        var others = arrays.slice(0);
        others.splice(i, 1);
        var otherValues = Array.prototype.concat.apply([], others);
        var unique = otherValues.filter(function (x, j) { 
            return otherValues.indexOf(x) === j; 
        });
        diff = diff.concat(arr.filter(x => unique.indexOf(x) === -1));
    });
    return diff;
}

Example:

// diff between two arrays:
const a = ['a', 'd', 'e'];
const b = ['a', 'b', 'c', 'd'];
arrayDiff(a, b); // (3) ["e", "b", "c"]

// diff between multiple arrays
const a = ['b', 'c', 'd', 'e', 'g'];
const b = ['a', 'b'];
const c = ['a', 'e', 'f'];
arrayDiff(a, b, c); // (4) ["c", "d", "g", "f"]

Difference between Arrays of Objects

function arrayDiffByKey(key, ...arrays) {
    return [].concat(...arrays.map( (arr, i) => {
        const others = arrays.slice(0);
        others.splice(i, 1);
        const unique = [...new Set([].concat(...others))];
        return arr.filter( x =>
            !unique.some(y => x[key] === y[key])
        );
    }));
}

Example:

const a = [{k:1}, {k:2}, {k:3}];
const b = [{k:1}, {k:4}, {k:5}, {k:6}];
const c = [{k:3}, {k:5}, {k:7}];
arrayDiffByKey('k', a, b, c); // (4) [{k:2}, {k:4}, {k:6}, {k:7}]
Luca Borrione
  • 16,324
  • 8
  • 52
  • 66
52

You could use a Set in this case. It is optimized for this kind of operation (union, intersection, difference).

Make sure it applies to your case, once it allows no duplicates.

var a = new JS.Set([1,2,3,4,5,6,7,8,9]);
var b = new JS.Set([2,4,6,8]);

a.difference(b)
// -> Set{1,3,5,7,9}
Samuel Carrijo
  • 17,449
  • 12
  • 49
  • 59
  • 4
    That looks like a nice library! What a shame that you can't download just the `Set` function without having to get everything else... – Blixt Jul 27 '09 at 10:48
  • @Blixt I believe you can download it all, and just include just the set.js file – Samuel Carrijo Jul 27 '09 at 10:52
  • Set is implemented in google closure as well. http://closure-library.googlecode.com/svn/docs/class_goog_structs_Set.html – Ben Flynn Feb 06 '12 at 19:08
  • 2
    Wow, it's been 1 year? https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set – Loupax Feb 07 '18 at 14:31
  • 6
    @Loupax Unfortunately the built-in ES Set doesn't have this handy `difference` method. – Charles Wood Jul 07 '21 at 21:58
44

One Liners

const unique = (a) => [...new Set(a)];
const uniqueBy = (x,f)=>Object.values(x.reduce((a,b)=>((a[f(b)]=b),a),{}));
const intersection = (a, b) => a.filter((v) => b.includes(v));
const diff = (a, b) => a.filter((v) => !b.includes(v));
const symDiff = (a, b) => diff(a, b).concat(diff(b, a));
const union = (a, b) => diff(a, b).concat(b);

const a = unique([1, 2, 3, 4, 5, 5]);
console.log(a);
const b = [4, 5, 6, 7, 8];

console.log(intersection(a, b), diff(a, b), symDiff(a, b), union(a, b));

console.log(uniqueBy(
  [
{ id: 1, name: "abc" },
{ id: 2, name: "xyz" },
{ id: 1, name: "abc" },
  ],
  (v) => v.id
));

const intersectionBy = (a, b, f) => a.filter((v) => b.some((u) => f(v, u)));

console.log(intersectionBy(
 [
  { id: 1, name: "abc" },
  { id: 2, name: "xyz" },
 ],
 [
  { id: 1, name: "abc" },
  { id: 3, name: "pqr" },
 ],
 (v, u) => v.id === u.id
));

const diffBy = (a, b, f) => a.filter((v) => !b.some((u) => f(v, u)));

console.log(diffBy(
 [
  { id: 1, name: "abc" },
  { id: 2, name: "xyz" },
 ],
 [
  { id: 1, name: "abc" },
  { id: 3, name: "pqr" },
 ],
 (v, u) => v.id === u.id
));

TypeScript

playground link

const unique = <T>(array: T[]) => [...new Set(array)];


const intersection = <T>(array1: T[], array2: T[]) =>
  array1.filter((v) => array2.includes(v));


const diff = <T>(array1: T[], array2: T[]) =>
  array1.filter((v) => !array2.includes(v));


const symDiff = <T>(array1: T[], array2: T[]) =>
  diff(array1, array2).concat(diff(array2, array1));


const union = <T>(array1: T[], array2: T[]) =>
  diff(array1, array2).concat(array2);


const intersectionBy = <T>(
  array1: T[],
  array2: T[],
  predicate: (array1Value: T, array2Value: T) => boolean
) => array1.filter((v) => array2.some((u) => predicate(v, u)));


const diffBy = <T>(
  array1: T[],
  array2: T[],
  predicate: (array1Value: T, array2Value: T) => boolean
) => array1.filter((v) => !array2.some((u) => predicate(v, u)));


const uniqueBy = <T>(
  array: T[],
  predicate: (v: T, i: number, a: T[]) => string
) =>
  Object.values(
    array.reduce((acc, value, index) => {
      acc[predicate(value, index, array)] = value;
      return acc;
    }, {} as { [key: string]: T })
  );
nkitku
  • 4,779
  • 1
  • 31
  • 27
34
function diff(a1, a2) {
  return a1.concat(a2).filter(function(val, index, arr){
    return arr.indexOf(val) === arr.lastIndexOf(val);
  });
}

Merge both the arrays, unique values will appear only once so indexOf() will be the same as lastIndexOf().

pdbrito
  • 552
  • 8
  • 13
  • 3
    I agree this is the cleanest and simplest way and nice that it doesn't require touching prototype. “If you can't explain it to a six year old, you don't understand it yourself.” ― Albert Einstein – lacostenycoder Oct 09 '15 at 18:03
33

With the arrival of ES6 with sets and splat operator (at the time of being works only in Firefox, check compatibility table), you can write the following one liner:

var a = ['a', 'b', 'c', 'd'];
var b = ['a', 'b'];
var b1 = new Set(b);
var difference = [...new Set(a.filter(x => !b1.has(x)))];

which will result in [ "c", "d" ].

Magne
  • 16,401
  • 10
  • 68
  • 88
Salvador Dali
  • 214,103
  • 147
  • 703
  • 753
  • Just curious how is that any different than doing `b.filter(x => !a.indexOf(x)))` – chovy Jun 15 '15 at 08:03
  • 2
    @chovy it is different in time complexity. My solution is `O(n + m)` your solution is `O(n * m)` where n and m are lengths of arrays. Take long lists and my solution will run in seconds, while yours will take hours. – Salvador Dali Jun 15 '15 at 08:28
  • 1
    What about comparing an attribute of a list of objects? Is that possible using this solution? – chovy Jun 15 '15 at 08:30
  • @chovy what do you mean by **comparing an attribute of a list of objects**? – Salvador Dali Jun 15 '15 at 08:57
  • 3
    `a.filter(x => !b1.has(x))` is simpler. And note the spec only requires the complexity to be `n * f(m) + m` with `f(m)` sublinear on average. It's better than `n * m`, but not necessarily `n + m`. – Oriol Dec 16 '15 at 22:19
  • 3
    @SalvadorDali `var difference = [...new Set([...a].filter(x => !b1.has(x)))];` Why are you creating duplicate 'a' array? Why are you turning result of filter into a set and then back into array? Isn't this equivalent to `var difference = a.filter(x => !b1.has(x));` – Deepak Mittal Jul 13 '18 at 19:06
  • @DeepakMittal You are correct, so fixed it in an edit now. I think he presumed that `a` was a Set, because then it would have to be converted to an array to run filter on it. – Magne Dec 01 '20 at 18:13
  • This will work provided you know that "a" is the array containing the extra elements i.e the larger array. To find a difference irrespective of size, one should find the larger of the two first, then proceed. – KJ Sudarshan Feb 06 '21 at 17:58
17

to subtract one array from another, simply use the snippet below:

var a1 = ['1','2','3','4','6'];
var a2 = ['3','4','5'];

var items = new Array();

items = jQuery.grep(a1,function (item) {
    return jQuery.inArray(item, a2) < 0;
});

It will returns ['1,'2','6'] that are items of first array which don't exist in the second.

Therefore, according to your problem sample, following code is the exact solution:

var array1 = ["test1", "test2","test3", "test4"];
var array2 = ["test1", "test2","test3","test4", "test5", "test6"];

var _array = new Array();

_array = jQuery.grep(array2, function (item) {
     return jQuery.inArray(item, array1) < 0;
});
Alchi
  • 799
  • 9
  • 19
16

Another way to solve the problem

function diffArray(arr1, arr2) {
    return arr1.concat(arr2).filter(function (val) {
        if (!(arr1.includes(val) && arr2.includes(val)))
            return val;
    });
}

diffArray([1, 2, 3, 7], [3, 2, 1, 4, 5]);    // return [7, 4, 5]

Also, you can use arrow function syntax:

const diffArray = (arr1, arr2) => arr1.concat(arr2)
    .filter(val => !(arr1.includes(val) && arr2.includes(val)));

diffArray([1, 2, 3, 7], [3, 2, 1, 4, 5]);    // return [7, 4, 5]
Yurii Holskyi
  • 878
  • 1
  • 13
  • 28
14

Functional approach with ES2015

Computing the difference between two arrays is one of the Set operations. The term already indicates that the native Set type should be used, in order to increase the lookup speed. Anyway, there are three permutations when you compute the difference between two sets:

[+left difference] [-intersection] [-right difference]
[-left difference] [-intersection] [+right difference]
[+left difference] [-intersection] [+right difference]

Here is a functional solution that reflects these permutations.

Left difference:

// small, reusable auxiliary functions

const apply = f => x => f(x);
const flip = f => y => x => f(x) (y);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));


// left difference

const differencel = xs => ys => {
  const zs = createSet(ys);
  return filter(x => zs.has(x)
     ? false
     : true
  ) (xs);
};


// mock data

const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,3,6,7,8,9];


// run the computation

console.log( differencel(xs) (ys) );

Right difference:

differencer is trivial. It is just differencel with flipped arguments. You can write a function for convenience: const differencer = flip(differencel). That's all!

Symmetric difference:

Now that we have the left and right one, implementing the symmetric difference gets trivial as well:

// small, reusable auxiliary functions

const apply = f => x => f(x);
const flip = f => y => x => f(x) (y);
const concat = y => xs => xs.concat(y);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));


// left difference

const differencel = xs => ys => {
  const zs = createSet(ys);
  return filter(x => zs.has(x)
     ? false
     : true
  ) (xs);
};


// symmetric difference

const difference = ys => xs =>
 concat(differencel(xs) (ys)) (flip(differencel) (xs) (ys));

// mock data

const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,3,6,7,8,9];


// run the computation

console.log( difference(xs) (ys) );

I guess this example is a good starting point to obtain an impression what functional programming means:

Programming with building blocks that can be plugged together in many different ways.

12

A solution using indexOf() will be ok for small arrays but as they grow in length the performance of the algorithm approaches O(n^2). Here's a solution that will perform better for very large arrays by using objects as associative arrays to store the array entries as keys; it also eliminates duplicate entries automatically but only works with string values (or values which can be safely stored as strings):

function arrayDiff(a1, a2) {
  var o1={}, o2={}, diff=[], i, len, k;
  for (i=0, len=a1.length; i<len; i++) { o1[a1[i]] = true; }
  for (i=0, len=a2.length; i<len; i++) { o2[a2[i]] = true; }
  for (k in o1) { if (!(k in o2)) { diff.push(k); } }
  for (k in o2) { if (!(k in o1)) { diff.push(k); } }
  return diff;
}

var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];
arrayDiff(a1, a2); // => ['c', 'd']
arrayDiff(a2, a1); // => ['c', 'd']
maerics
  • 151,642
  • 46
  • 269
  • 291
  • You want to use Object.hasOwnProperty() whenever you're doing a "for in" on an object. Otherwise you run the risk of looping through every field added to the prototype of the default Object. (Or just your object's parent) Also you only need two loops, one for a hash table creation, and the other looks up on that hash table. – jholloman Sep 06 '12 at 18:16
  • 1
    @jholloman I [respectfully disagree](http://phrogz.net/death-to-hasownproperty). Now that we can control enumerability for any property, presumably you *should* be including any property that you get during enumeration. – Phrogz Jan 18 '13 at 20:20
  • 1
    @Phrogz A good point if you are only worried about modern browsers. Unfortunately I have to support back to IE7 at work so stone age is my default train of thought and we don't tend to use shims. – jholloman Jan 19 '13 at 02:36
10

The above answer by Joshaven Potter is great. But it returns elements in array B that are not in array C, but not the other way around. For example, if var a=[1,2,3,4,5,6].diff( [3,4,5,7]); then it will output: ==> [1,2,6], but not [1,2,6,7], which is the actual difference between the two. You can still use Potter's code above but simply redo the comparison once backwards too:

Array.prototype.diff = function(a) {
    return this.filter(function(i) {return !(a.indexOf(i) > -1);});
};

////////////////////  
// Examples  
////////////////////

var a=[1,2,3,4,5,6].diff( [3,4,5,7]);
var b=[3,4,5,7].diff([1,2,3,4,5,6]);
var c=a.concat(b);
console.log(c);

This should output: [ 1, 2, 6, 7 ]

rationalboss
  • 5,330
  • 3
  • 30
  • 50
user1685068
  • 101
  • 1
  • 2
8

Very Simple Solution with the filter function of JavaScript:

var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];

function diffArray(arr1, arr2) {
  var newArr = [];
  var myArr = arr1.concat(arr2);
  
    newArr = myArr.filter(function(item){
      return arr2.indexOf(item) < 0 || arr1.indexOf(item) < 0;
    });
   alert(newArr);
}

diffArray(a1, a2);
Yash Thakkar
  • 81
  • 1
  • 2
7
Array.prototype.difference = function(e) {
    return this.filter(function(i) {return e.indexOf(i) < 0;});
};

eg:- 

[1,2,3,4,5,6,7].difference( [3,4,5] );  
 => [1, 2, 6 , 7]
Riyas TK
  • 1,231
  • 6
  • 18
  • 32
  • You should never extend a native object this way. If the standard introduces `difference` as function in a future version and this function then has a different function signature then yours, it will break your code or foreign libraries that use this function. – t.niese Jul 25 '17 at 11:32
7

If you have two list of objects

const people = [{name: 'cesar', age: 23}]
const morePeople = [{name: 'cesar', age: 23}, {name: 'kevin', age: 26}, {name: 'pedro', age: 25}]

let result2 = morePeople.filter(person => people.every(person2 => !person2.name.includes(person.name)))
Vikas Gupta
  • 1,293
  • 1
  • 15
  • 21
  • This is a great answer. I upvote this. Most of the time you will be working with arrays that contain objects..... This helped me today. Thank you Vikas – KingJoeffrey Feb 22 '22 at 23:21
6

How about this:

Array.prototype.contains = function(needle){
  for (var i=0; i<this.length; i++)
    if (this[i] == needle) return true;

  return false;
} 

Array.prototype.diff = function(compare) {
    return this.filter(function(elem) {return !compare.contains(elem);})
}

var a = new Array(1,4,7, 9);
var b = new Array(4, 8, 7);
alert(a.diff(b));

So this way you can do array1.diff(array2) to get their difference (Horrible time complexity for the algorithm though - O(array1.length x array2.length) I believe)

Cat
  • 7,042
  • 8
  • 34
  • 36
  • Using the filter option is a great idea... however, you don't need to create a contains method for Array. I converted your idea into a one liner... Thanks for the inspiration! – Joshaven Potter Oct 26 '10 at 18:39
  • You don't need to define the contains() function. JS includes() does the same thing. – Da Man Jan 12 '19 at 08:37
6
function diffArray(arr1, arr2) {
  var newArr = arr1.concat(arr2);
  return newArr.filter(function(i){
    return newArr.indexOf(i) == newArr.lastIndexOf(i);
  });
}

this is works for me

Stan D
  • 61
  • 1
  • 1
6
const a1 = ['a', 'b', 'c', 'd'];
const a2 = ['a', 'b'];

const diffArr = a1.filter(o => !a2.includes(o));

console.log(diffArr);

Output:

[ 'a', 'b' ]
Korayem
  • 12,108
  • 5
  • 69
  • 56
Manu Rastogi
  • 188
  • 1
  • 7
5

To find the difference of 2 arrays without duplicates:

function difference(arr1, arr2){

  let setA = new Set(arr1);
  let differenceSet = new Set(arr2.filter(ele => !setA.has(ele)));
  return [...differenceSet ];

}

1.difference([2,2,3,4],[2,3,3,4]) will return []

2.difference([1,2,3],[4,5,6]) will return [4,5,6]

3.difference([1,2,3,4],[1,2]) will return []

4.difference([1,2],[1,2,3,4]) will return [3,4]

Note: The above solution requires that you always send the larger array as the second parameter. To find the absolute difference, you will need to first find the larger array of the two and then work on them.

To find the absolute difference of 2 arrays without duplicates:

function absDifference(arr1, arr2){

  const {larger, smaller} = arr1.length > arr2.length ? 
  {larger: arr1, smaller: arr2} : {larger: arr2, smaller: arr1}
  
  let setA = new Set(smaller);
  let absDifferenceSet = new Set(larger.filter(ele => !setA.has(ele)));
  return [...absDifferenceSet ];

}

1.absDifference([2,2,3,4],[2,3,3,4]) will return []

2.absDifference([1,2,3],[4,5,6]) will return [4,5,6]

3.absDifference([1,2,3,4],[1,2]) will return [3,4]

4.absDifference([1,2],[1,2,3,4]) will return [3,4]

Note the example 3 from both the solutions

KJ Sudarshan
  • 2,694
  • 1
  • 29
  • 22
4
  • Pure JavaScript solution (no libraries)
  • Compatible with older browsers (doesn't use filter)
  • O(n^2)
  • Optional fn callback parameter that lets you specify how to compare array items

function diff(a, b, fn){
    var max = Math.max(a.length, b.length);
        d = [];
    fn = typeof fn === 'function' ? fn : false
    for(var i=0; i < max; i++){
        var ac = i < a.length ? a[i] : undefined
            bc = i < b.length ? b[i] : undefined;
        for(var k=0; k < max; k++){
            ac = ac === undefined || (k < b.length && (fn ? fn(ac, b[k]) : ac == b[k])) ? undefined : ac;
            bc = bc === undefined || (k < a.length && (fn ? fn(bc, a[k]) : bc == a[k])) ? undefined : bc;
            if(ac == undefined && bc == undefined) break;
        }
        ac !== undefined && d.push(ac);
        bc !== undefined && d.push(bc);
    }
    return d;
}

alert(
    "Test 1: " + 
    diff(
        [1, 2, 3, 4],
        [1, 4, 5, 6, 7]
      ).join(', ') +
    "\nTest 2: " +
    diff(
        [{id:'a',toString:function(){return this.id}},{id:'b',toString:function(){return this.id}},{id:'c',toString:function(){return this.id}},{id:'d',toString:function(){return this.id}}],
        [{id:'a',toString:function(){return this.id}},{id:'e',toString:function(){return this.id}},{id:'f',toString:function(){return this.id}},{id:'d',toString:function(){return this.id}}],
        function(a, b){ return a.id == b.id; }
    ).join(', ')
);
Trevor
  • 13,085
  • 13
  • 76
  • 99
  • You can cache length values to squeeze some more speed. I wanted to recommend accessing array elements without checking for length, but apparently that simple check yields almost 100x speedup. – Slotos Nov 20 '14 at 02:50
  • No reason to cache `length` values. It's already plain property. https://jsperf.com/array-length-caching – vp_arth Nov 14 '15 at 16:06
4

Using http://phrogz.net/JS/ArraySetMath.js you can:

var array1 = ["test1", "test2","test3", "test4"];
var array2 = ["test1", "test2","test3","test4", "test5", "test6"];

var array3 = array2.subtract( array1 );
// ["test5", "test6"]

var array4 = array1.exclusion( array2 );
// ["test5", "test6"]
Phrogz
  • 296,393
  • 112
  • 651
  • 745
4

Here is another solution that can return the differences, just like git diff: (it has been written in typescript, if you're not using typescript version, just remove the types)

/**
 * util function to calculate the difference between two arrays (pay attention to 'from' and 'to'),
 * it would return the mutations from 'from' to 'to' 
 * @param { T[] } from
 * @param { T[] } to
 * @returns { { [x in string]: boolean } } it would return the stringified version of array element, true means added,
 * false means removed
 */
export function arrDiff<T>(from: T[], to: T[]): { [x in string]: boolean } {

  var diff: { [x in string]: boolean } = {};
  var newItems: T[] = []
  diff = from.reduce((a, e) => ({ ...a, [JSON.stringify(e)]: true }), {})

  for (var i = 0; i < to.length; i++) {
    if (diff[JSON.stringify(to[i])]) {
      delete diff[JSON.stringify(to[i])]
    } else {
      newItems.push(to[i])
    }
  }

  return {
    ...Object.keys(diff).reduce((a, e) => ({ ...a, [e]: false }), {}),
    ...newItems.reduce((a, e) => ({ ...a, [JSON.stringify(e)]: true }), {})
  }
}

Here is a sample of usage:

arrDiff(['a', 'b', 'c'], ['a', 'd', 'c', 'f']) //{"b": false, "d": true, "f": true}
Aliunco
  • 399
  • 2
  • 9
3

You can use underscore.js : http://underscorejs.org/#intersection

You have needed methods for array :

_.difference([1, 2, 3, 4, 5], [5, 2, 10]);
=> [1, 3, 4]

_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2]
Sebastien
  • 6,640
  • 14
  • 57
  • 105
3

This is working: basically merge the two arrays, look for the duplicates and push what is not duplicated into a new array which is the difference.

function diff(arr1, arr2) {
  var newArr = [];
  var arr = arr1.concat(arr2);
  
  for (var i in arr){
    var f = arr[i];
    var t = 0;
    for (j=0; j<arr.length; j++){
      if(arr[j] === f){
        t++; 
        }
    }
    if (t === 1){
      newArr.push(f);
        }
  } 
  return newArr;
}
ggglni
  • 79
  • 3
3

I wanted a similar function which took in an old array and a new array and gave me an array of added items and an array of removed items, and I wanted it to be efficient (so no .contains!).

You can play with my proposed solution here: http://jsbin.com/osewu3/12.

Can anyone see any problems/improvements to that algorithm? Thanks!

Code listing:

function diff(o, n) {
  // deal with empty lists
  if (o == undefined) o = [];
  if (n == undefined) n = [];

  // sort both arrays (or this won't work)
  o.sort(); n.sort();

  // don't compare if either list is empty
  if (o.length == 0 || n.length == 0) return {added: n, removed: o};

  // declare temporary variables
  var op = 0; var np = 0;
  var a = []; var r = [];

  // compare arrays and add to add or remove lists
  while (op < o.length && np < n.length) {
      if (o[op] < n[np]) {
          // push to diff?
          r.push(o[op]);
          op++;
      }
      else if (o[op] > n[np]) {
          // push to diff?
          a.push(n[np]);
          np++;
      }
      else {
          op++;np++;
      }
  }

  // add remaining items
  if( np < n.length )
    a = a.concat(n.slice(np, n.length));
  if( op < o.length )
    r = r.concat(o.slice(op, o.length));

  return {added: a, removed: r}; 
}
Ian Grainger
  • 5,148
  • 3
  • 46
  • 72
3

//es6 approach

function diff(a, b) {
  var u = a.slice(); //dup the array
  b.map(e => {
    if (u.indexOf(e) > -1) delete u[u.indexOf(e)]
    else u.push(e)   //add non existing item to temp array
  })
  return u.filter((x) => {return (x != null)}) //flatten result
}
copremesis
  • 758
  • 7
  • 7
3

Symmetric and linear complexity. Requires ES6.

function arrDiff(arr1, arr2) {
    var arrays = [arr1, arr2].sort((a, b) => a.length - b.length);
    var smallSet = new Set(arrays[0]);

    return arrays[1].filter(x => !smallSet.has(x));
}
Dodgie
  • 643
  • 1
  • 10
  • 17
3

yet another answer, but seems nobody mentioned jsperf where they compare several algorithms and technology support: https://jsperf.com/array-difference-javascript seems using filter gets the best results. thanks

cancerbero
  • 6,799
  • 1
  • 32
  • 24
3

Use extra memory to do this. That way you can solve it with less time complexity, O(n) instead of o(n*n).

function getDiff(arr1,arr2){
let k = {};
let diff = []
arr1.map(i=>{
    if (!k.hasOwnProperty(i)) {
        k[i] = 1
    }
}
)
arr2.map(j=>{
    if (!k.hasOwnProperty(j)) {
        k[j] = 1;
    } else {
        k[j] = 2;
    }
}
)
for (var i in k) {
    if (k[i] === 1)
        diff.push(+i)
}
return diff
}
getDiff([4, 3, 52, 3, 5, 67, 9, 3],[4, 5, 6, 75, 3, 334, 5, 5, 6])
Ashish Yadav
  • 3,039
  • 1
  • 16
  • 23
3

try it.

var first = [ 1, 2, 3, 4, 5 ];
    var second = [ 4, 5, 6 ];
     
    var difference = first.filter(x => second.indexOf(x) === -1);
    console.log(difference);


Output: [ 1, 2, 3]

var first = [ 1, 2, 3, 4, 5 ];
    var second = [ 4, 5, 6 ];
     
    var difference = first.filter(x => second.indexOf(x) === -1);
    console.log(difference);
raddevus
  • 8,142
  • 7
  • 66
  • 87
hamedkke
  • 47
  • 1
  • 3
  • 1
    This is not correct. Try `var first = [ 4, 5, 6 ];` and `var second = [ 1, 2, 3, 4, 5, 6 ];` – Matt Mar 05 '22 at 11:15
3

If you want to find the difference between two arrays of object you can do it like this :

let arrObj = [{id: 1},{id: 2},{id: 3}]
let arrObj2 = [{id: 1},{id: 3}]

let result = arrObj.filter(x => arrObj2.every(x2 => x2.id !== x.id))

console.log(result)
crg
  • 4,284
  • 2
  • 29
  • 57
3
const dbData = [{name:'ally'}, 
{name:'James'}]
const localData = [{name:'James'}] 

const diff = dbData.filter(a =>!localData.some(b => { return a.name === b.name}))
  • 3
    While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. You can find more information on how to write good answers in the help center: https://stackoverflow.com/help/how-to-answer . Good luck – nima Nov 03 '22 at 08:35
2

littlebit fix for the best answer

function arr_diff(a1, a2)
{
  var a=[], diff=[];
  for(var i=0;i<a1.length;i++)
    a[a1[i]]=a1[i];
  for(var i=0;i<a2.length;i++)
    if(a[a2[i]]) delete a[a2[i]];
    else a[a2[i]]=a2[i];
  for(var k in a)
   diff.push(a[k]);
  return diff;
}

this will take current type of element in consideration. b/c when we make a[a1[i]] it converts a value to string from its oroginal value, so we lost actual value.

  • This still fails for an array of objects. var a = [{a: 1}], b = [{b: 2}] arr_diff(a,b) == []. – EricP Jul 03 '15 at 04:41
2
var result = [];
var arr1 = [1,2,3,4];
var arr2 = [2,3];
arr1.forEach(function(el, idx) {
    function unEqual(element, index, array) {
        var a = el;
        return (element!=a);
    }
    if (arr2.every(unEqual)) {
        result.push(el);
    };
});
alert(result);
fog
  • 31
  • 1
2

This was inspired by the accepted answer by Thinker, but Thinker's answer seems to assume the arrays are sets. It falls apart if the arrays are [ "1", "2" ] and [ "1", "1", "2", "2" ]

The difference between those arrays is [ "1", "2" ]. The following solution is O(n*n), so not ideal, but if you have big arrays, it has memory advantages over Thinker's solution as well.

If you're dealing with sets in the first place, Thinker's solution is definitely better. If you have a newer version of Javascript with access to filters, you should use those as well. This is only for those who aren't dealing with sets and are using an older version of JavaScript (for whatever reason)...

if (!Array.prototype.diff) { 
    Array.prototype.diff = function (array) {
        // if the other array is a falsy value, return a copy of this array
        if ((!array) || (!Array.prototype.isPrototypeOf(array))) { 
            return this.slice(0);
        }

        var diff = [];
        var original = this.slice(0);

        for(var i=0; i < array.length; ++i) {
            var index = original.indexOf(array[i]);
            if (index > -1) { 
                original.splice(index, 1);
            } else { 
                diff.push(array[i]);
            }
        }

        for (var i=0; i < original.length; ++i) {
            diff.push(original[i]);
        }
        return diff;
    }
}   
redusek
  • 77
  • 4
2

Quick solution. Although it seems that others have already posted different variations of the same method. I am not sure this is the best for huge arrays, but it works for my arrays which won't be larger than 10 or 15.

Difference b - a

for(var i = 0; i < b.length; i++){
  for(var j = 0; j < a.length; j ++){
    var loc = b.indexOf(a[j]);
    if(loc > -1){
      b.splice(loc, 1);
    }
  }
}
Ajoy
  • 1,838
  • 3
  • 30
  • 57
2

Simply compares all values and returns array with the values that do not repeat.

var main = [9, '$', 'x', 'r', 3, 'A', '#', 0, 1];

var arr0 = ['Z', 9, 'e', '$', 'r'];
var arr1 = ['x', 'r', 3, 'A', '#'];
var arr2 = ['m', '#', 'a', 0, 'r'];
var arr3 = ['$', 1, 'n', '!', 'A'];


Array.prototype.diff = function(arrays) {
    var items = [].concat.apply(this, arguments);
    var diff = [].slice.call(items), i, l, x, pos;

    // go through all items
    for (x = 0, i = 0, l = items.length; i < l; x = 0, i++) {
        // find all positions
        while ((pos = diff.indexOf(items[i])) > -1) {
            // remove item + increase found count
            diff.splice(pos, 1) && x++;
        }
        // if item was found just once, put it back
        if (x === 1) diff.push(items[i]);
    }
    // get all not duplicated items
    return diff;
};

main.diff(arr0, arr1, arr2, arr3).join(''); // returns "Zeman!"

[].diff(main, arr0, arr1, arr2, arr3).join(''); // returns "Zeman!"
MarekZeman91
  • 109
  • 1
  • 3
  • You should never extend a native object this way. If the standard introduces `diff` as function in a future version and this function then has a different function signature then yours, it will break your code or foreign libraries that use this function. – t.niese Jul 25 '17 at 11:31
  • @t.niese Well, nobody says you have to use it. You might not notice but it's a common thing to extend native object if you need or want it. For sure it can make problems later but smart developer will quickly find out how to use the new version ;) – MarekZeman91 Jul 26 '17 at 12:58
  • 1
    @MarekZeman91 Well, as the saying goes, a smart developer can fix problems that a wise developer knows to avoid in the first place. – Guy Passy Jan 11 '18 at 10:42
2
function diff(arr1, arr2) {
  var filteredArr1 = arr1.filter(function(ele) {
    return arr2.indexOf(ele) == -1;
  });

  var filteredArr2 = arr2.filter(function(ele) {
    return arr1.indexOf(ele) == -1;
  });
  return filteredArr1.concat(filteredArr2);
}

diff([1, "calf", 3, "piglet"], [1, "calf", 3, 4]); // Log ["piglet",4]
huy-tran
  • 21
  • 2
2

If the arrays are not of simple types, then one of the above answers can be adapted:

Array.prototype.diff = function(a) {
        return this.filter(function(i) {return a.map(function(e) { return JSON.stringify(e); }).indexOf(JSON.stringify(i)) < 0;});
    };

This method works on arrays of complex objects.

AVANG
  • 71
  • 2
  • 9
2
var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];
var diff = [];
for (var i in a2) {
   var found = false;
   for (var j in a1) {
      if (a2[i] === a1[j]) found = true;
   }
   if (found === false) diff.push(a2[i]);
}

That simple. Could use with objects also, checking one property of object. Like,

if (a2[i].id === a1[j].id) found = true;
2

Similar to Ian Grainger's solution (but in typescript):

function findDiffs(arrayOne: string[], arrayTwo: string[]) {

    let onlyInArrayOne = []
    let onlyInArrayTwo = []
    let share = []
    let [arrayOneCopy, arrayTwoCopy] = [[...arrayOne], [...arrayTwo]]

    arrayOneCopy.sort(); arrayTwoCopy.sort()

    while (arrayOneCopy.length !== 0 && arrayTwoCopy.length !== 0) {
        if (arrayOneCopy[0] == arrayTwoCopy[0]) {
            share.push(arrayOneCopy[0])
            arrayOneCopy.splice(0, 1)
            arrayTwoCopy.splice(0, 1)
        }
        if (arrayOneCopy[0] < arrayTwoCopy[0]) {
            onlyInArrayOne.push(arrayOneCopy[0])
            arrayOneCopy.splice(0, 1)
        }
        if (arrayOneCopy[0] > arrayTwoCopy[0]) {
            onlyInArrayTwo.push(arrayTwoCopy[0])
            arrayTwoCopy.splice(0, 1)
        }
    }
    onlyInArrayTwo = onlyInArrayTwo.concat(arrayTwoCopy)
    onlyInArrayOne = onlyInArrayOne.concat(arrayOneCopy)

    return {
        onlyInArrayOne,
        onlyInArrayTwo,
        share,
        diff: onlyInArrayOne.concat(onlyInArrayTwo)
    }
}

// arrayOne: [ 'a', 'b', 'c', 'm', 'y' ] 
// arrayTwo: [ 'c', 'b', 'f', 'h' ]
//
// Results: 
// { 
//    onlyInArrayOne: [ 'a', 'm', 'y' ],
//    onlyInArrayTwo: [ 'f', 'h' ],
//    share: [ 'b', 'c' ],
//    diff: [ 'a', 'm', 'y', 'f', 'h' ] 
// }
2

I was looking for a simple answer that didn't involve using different libraries, and I came up with my own that I don't think has been mentioned here. I don't know how efficient it is or anything but it works;

    function find_diff(arr1, arr2) {
      diff = [];
      joined = arr1.concat(arr2);
      for( i = 0; i <= joined.length; i++ ) {
        current = joined[i];
        if( joined.indexOf(current) == joined.lastIndexOf(current) ) {
          diff.push(current);
        }
      }
      return diff;
    }

For my code I need duplicates taken out as well, but I guess that isn't always preferred.

I guess the main downside is it's potentially comparing many options that have already been rejected.

Samuel
  • 21
  • 1
1

Just thinking... for the sake of a challenge ;-) would this work... (for basic arrays of strings, numbers, etc.) no nested arrays

function diffArrays(arr1, arr2, returnUnion){
  var ret = [];
  var test = {};
  var bigArray, smallArray, key;
  if(arr1.length >= arr2.length){
    bigArray = arr1;
    smallArray = arr2;
  } else {
    bigArray = arr2;
    smallArray = arr1;
  }
  for(var i=0;i<bigArray.length;i++){
    key = bigArray[i];
    test[key] = true;
  }
  if(!returnUnion){
    //diffing
    for(var i=0;i<smallArray.length;i++){
      key = smallArray[i];
      if(!test[key]){
        test[key] = null;
      }
    }
  } else {
    //union
    for(var i=0;i<smallArray.length;i++){
      key = smallArray[i];
      if(!test[key]){
        test[key] = true;
      }
    }
  }
  for(var i in test){
    ret.push(i);
  }
  return ret;
}

array1 = "test1", "test2","test3", "test4", "test7"
array2 = "test1", "test2","test3","test4", "test5", "test6"
diffArray = diffArrays(array1, array2);
//returns ["test5","test6","test7"]

diffArray = diffArrays(array1, array2, true);
//returns ["test1", "test2","test3","test4", "test5", "test6","test7"]

Note the sorting will likely not be as noted above... but if desired, call .sort() on the array to sort it.

scunliffe
  • 62,582
  • 25
  • 126
  • 161
1

If not use hasOwnProperty then we have incorrect elements. For example:

[1,2,3].diff([1,2]); //Return ["3", "remove", "diff"] This is the wrong version

My version:

Array.prototype.diff = function(array2)
  {
    var a = [],
        diff = [],
        array1 = this || [];

    for (var i = 0; i < array1.length; i++) {
      a[array1[i]] = true;
    }
    for (var i = 0; i < array2.length; i++) {
      if (a[array2[i]]) {
        delete a[array2[i]];
      } else {
        a[array2[i]] = true;
      }
    }

    for (var k in a) {
      if (!a.hasOwnProperty(k)){
        continue;
      }
      diff.push(k);
    }

    return diff;
  }
Aleksandr L
  • 400
  • 2
  • 5
1

Contributing with a jQuery solution that I'm currently using:

if (!Array.prototype.diff) {
    Array.prototype.diff = function (a) {
        return $.grep(this, function (i) { return $.inArray(i, a) === -1; });
    }; 
}
Johan
  • 35,120
  • 54
  • 178
  • 293
  • 2
    @DotNetWise This is the eqvivalent of Joshaven's answer above with jQuery methods. Did you downvote him as well? – Johan Oct 21 '13 at 12:38
1

CoffeeScript version:

diff = (val for val in array1 when val not in array2)
m.e.conroy
  • 3,508
  • 25
  • 27
1

The selected answer is only half right. You must compare the arrays both ways to get a complete answer.

const ids_exist = [
   '1234',
   '5678',
   'abcd',
]

const ids_new = [
  '1234',
  '5678',
  'efjk',
  '9999',
]

function __uniq_Filter (__array_1, __array_2) {
  const one_not_in_two = __array_1.filter(function (obj) {
    return __array_2.indexOf(obj) == -1
  })
  const two_not_in_one = __array_2.filter(function (obj) {
    return __array_1.indexOf(obj) == -1
  })
  return one_not_in_two.concat(two_not_in_one)
}

let uniq_filter = __uniq_Filter(ids_exist, ids_new)

console.log('uniq_filter', uniq_filter) // => [ 'abcd', 'efjk', '9999' ]
Flavio
  • 506
  • 4
  • 9
1

I agree with the solution of @luis-sieira

I created bit self explanatory function for beginners to understand easily step by step:

function difference(oneArr, twoArr){
  var newArr = [];
  newArr = oneArr.filter((item)=>{
      return !twoArr.includes(item)
  });
  console.log(newArr)
    let arr = twoArr.filter((item)=>{
        return !oneArr.includes(item)
     });
    newArr =  newArr.concat(arr);
  console.log(newArr)
}
difference([1, 2, 3, 5], [1, 2, 3, 4, 5])
Ayyaz Zafar
  • 2,015
  • 5
  • 26
  • 40
1

Based on previous answers... depends if you want an efficient or "nice oneliner" solution.

There are 3 approaches in general...

  • "manual iterative" (using indexOf) - naive with O(n2) complexity (slow)

    var array_diff_naive = function(a,b){
    
     var i, la = a.length, lb = b.length, res = [];
    
     if (!la) return b; else if (!lb) return a;
     for (i = 0; i < la; i++) {
         if (b.indexOf(a[i]) === -1) res.push(a[i]);
     }
     for (i = 0; i < lb; i++) {
         if (a.indexOf(b[i]) === -1) res.push(b[i]);
     }
     return res;
    }
    
  • "abstract iterative" (using filter and concat library methods) - syntactic sugar for manual iterative (looks nicer, still sucks)

    var array_diff_modern = function(a1,a2){
    
    
     return a1.filter(function(v) { return  !a2.includes(v); } )
         .concat(a2.filter(function(v) { return !a1.includes(v);}));
    }
    
  • "using hashtable" (using object keys) - much more efficient - only O(n), but has slightly limited range of input array values

     var array_diff_hash = function(a1,a2){
    
     var a = [], diff = [];
    
     for (var i = 0; i < a1.length; i++) {
         a[a1[i]] = true;
     }
    
     for (var i = 0; i < a2.length; i++) {
         if (a[a2[i]]) {
             delete a[a2[i]];
         } else {
             a[a2[i]] = true;
         }
     }
    
     for (var k in a) {
         diff.push(k);
     }
    
     return diff;
    }
    

See this on jsperf
https://jsperf.com/array-diff-algo

Lukáš Řádek
  • 1,273
  • 1
  • 11
  • 23
1
    function arrayDiff(a, b) {
      return a.concat(b).filter(val => !(b.includes(val)));
      //(or) return a.concat(b).filter(val => !(a.includes(val) && b.includes(val)));
    }
1

In response to the person who wanted to subtract one array from another...

If no more than say 1000 elements try this...

Setup a new variable to duplicate Array01 and call it Array03.

Now, use the bubble sort algorithm to compare the elements of Array01 with Array02 and whenever you find a match do the following to Array03...

 if (Array01[x]==Array02[y]) {Array03.splice(x,1);}

NB: We are modifying Array03 instead of Array01 so as not to screw up the nested loops of the bubble sort!

Finally, copy the contents of Array03 to Array01 with a simple assignment, and you're done.

MPS
  • 11
  • 1
  • It does not work for some times, can you tell me "If no more than say 1000 elements try this..." ur statement meaning.. – Ketav Jun 05 '20 at 10:31
1

Samuel: "For my code I need duplicates taken out as well, but I guess that isn't always preferred. I guess the main downside is it's potentially comparing many options that have already been rejected."

When comparing TWO lists, Arrays, etc, and the elements are less than 1000, the industry standard in the 3GL world is to use the bubble sort which avoids dupes.

The code would look something like this... (untested but it should work)

var Array01=new Array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P');
var Array02=new Array('X','B','F','W','Z','X','J','P','P','O','E','N','Q');
var Array03=Array01;

for(x=1; x<Array02.length; x++) {
 for(y=0; y<Array01.length-1; y++) {
  if (Array01[y]==Array02[x]) {Array03.splice(y,1);}}}

Array01=Array03;

To test the output...

for(y=0; y<Array01.length; y++) {document.write(Array01[y])}
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
MPS
  • 31
  • 2
0

There's a lot of problems with the answers I'm reading here that make them of limited value in practical programming applications.

First and foremost, you're going to want to have a way to control what it means for two items in the array to be "equal". The === comparison is not going to cut it if you're trying to figure out whether to update an array of objects based on an ID or something like that, which frankly is probably one of the most likely scenarios in which you will want a diff function. It also limits you to arrays of things that can be compared with the === operator, i.e. strings, ints, etc, and that's pretty much unacceptable for grown-ups.

Secondly, there are three state outcomes of a diff operation:

  1. elements that are in the first array but not in the second
  2. elements that are common to both arrays
  3. elements that are in the second array but not in the first

I think this means you need no less than 2 loops, but am open to dirty tricks if anybody knows a way to reduce it to one.

Here's something I cobbled together, and I want to stress that I ABSOLUTELY DO NOT CARE that it doesn't work in old versions of Microshaft browsers. If you work in an inferior coding environment like IE, it's up to you to modify it to work within the unsatisfactory limitations you're stuck with.

Array.defaultValueComparison = function(a, b) {
    return (a === b);
};

Array.prototype.diff = function(arr, fnCompare) {

    // validate params

    if (!(arr instanceof Array))
        arr = [arr];

    fnCompare = fnCompare || Array.defaultValueComparison;

    var original = this, exists, storage, 
        result = { common: [], removed: [], inserted: [] };

    original.forEach(function(existingItem) {

        // Finds common elements and elements that 
        // do not exist in the original array

        exists = arr.some(function(newItem) {
            return fnCompare(existingItem, newItem);
        });

        storage = (exists) ? result.common : result.removed;
        storage.push(existingItem);

    });

    arr.forEach(function(newItem) {

        exists = original.some(function(existingItem) {
            return fnCompare(existingItem, newItem);
        });

        if (!exists)
            result.inserted.push(newItem);

    });

    return result;

};
Mason Houtz
  • 109
  • 4
0

This question is old but is still the top hit for javascript array subtraction so I wanted to add the solution I am using. This fits for the following case:

var a1 = [1,2,2,3]
var a2 = [1,2]
//result = [2,3]

The following method will produced the desired result:

function arrayDifference(minuend, subtrahend) {
  for (var i = 0; i < minuend.length; i++) {
    var j = subtrahend.indexOf(minuend[i])
    if (j != -1) {
      minuend.splice(i, 1);
      subtrahend.splice(j, 1);
    }
  }
  return minuend;
}

It should be noted that the function does not include values from the subtrahend that are not present in the minuend:

var a1 = [1,2,3]
var a2 = [2,3,4]
//result = [1]
cazzer
  • 1,726
  • 2
  • 18
  • 29
0

just trimming the string to ensure.... spaces wont affect the diff

function arr_diff(a1, a2) {
    var a=[], diff=[];
    for(var i=0;i<a1.length;i++)
        a[a1[i]]=true;
    for(var i=0;i<a2.length;i++)
        if(a[a2[i].trim()]) delete a[a2[i].trim()];
    else a[a2[i].trim()]=true;
    for(var k in a)
        diff.push(k);
    return diff;
}
RichardBernards
  • 3,146
  • 1
  • 22
  • 30
Sivanagaiah
  • 153
  • 3
  • 10
0

I've tried all of these above but none worked when you needed to match without accepting duplicates.

For example:

var a1 = [1, 2, 1, 4], a2 = [1, 2, 4];

Would return an empty diff array because 2 would be found once in the second array, even though we need it to match twice.

So I've managed to fix something up:

Array.prototype.diff = function(a) {
    return this.filter(function(item) {
        match = a.indexOf(item);
        if (match)
            a.splice(match, 1);
        return match < 0;
    });
};
casraf
  • 21,085
  • 9
  • 56
  • 91
0

here's the function I use to get the difference between 2 arrays - It's good for numerical, string, mixed num/string arrays. not object literal within arrays / multidimentional arrays

function diff(arr1, arr2) {

    var x, 
        t;

    function uniq(a, b) {
        t = b;

        if( (b === 0 && x[b+1]!==a) || 
           (t > 0 && a !== x[b+1] && a !== x[b-1]) ) {
            return  a;
        }
    }


    x = arr1.concat(arr2).sort();

    return x.filter(uniq);
}

var a1 = ['a', 'b', 'e', 'c'],
    a2 = ['b', 'a', 'c', 'f' ];

diff(a1, a2);
jfab fab
  • 491
  • 1
  • 8
  • 19
0

If you're array contains objects it becomes a bit more difficult if you want to compare an attribute.

Luckily lodash makes this pretty easy using _contains and _.pluck:

var list1 = [{id: 1},{id: 2}];
var list1 = [{id: 1},{id: 2}, {id: 3}];

//es6
var results = list2.filter(item => {
  return !_.contains(_.pluck(list1, 'id'), item.id);
});

//es5
var results = list2.filter(function(item){
  return !_.contains(_.pluck(list1, 'id'), item.id);
});

//results contains [{id: 3}]
chovy
  • 72,281
  • 52
  • 227
  • 295
0

Here is what I use:

var newArr = a1.filter(function(elem) {
            return a2.indexOf(elem) === -1;
        }).concat( a2.filter(function(elem) {
            return a1.indexOf(elem) === -1;
        }));
console.log(newArr);

or this one

var newArr = a1.concat(a2);
        function check(item) {
            if (a1.indexOf(item) === -1 || a2.indexOf(item) === -1) {
                return item;
            }
        }
        return newArr.filter(check);
Koushik Das
  • 9,678
  • 3
  • 51
  • 50
0
var arrayDifference = function(arr1, arr2){
  if(arr1 && arr1.length){
    if(arr2 && arr2.length > 0){
      for (var i=0, itemIndex; i<arr2.length; i++){
        itemIndex = arr1.indexOf(arr2[i]);
        if(itemIndex !== -1){
          arr1.splice(itemIndex, 1);
        }
      }
    }
    return arr1;
  }
  return [];
};

arrayDifference([1,2,3,4,5], [1,5,6]);
Aswin Ramesh
  • 1,654
  • 1
  • 13
  • 13
0

The hard way (in case you would like to do something more fancy than .indexOf)

var difference = function (source, target) {
    return source.reduce(function (diff, current) { 
        if (target.indexOf(current) === -1) { 
            diff.push(current); 
        }

        return diff; 
    }, []);
}

The easy way

var difference = function (source, target) {
    return source.filter(function (current) {
        return target.indexOf(current) === -1;
    });
}
Santhos
  • 3,348
  • 5
  • 30
  • 48
0

Data:

var new_storage = JSON.parse('[{"id_order":"0003"},{"id_order":"0004"},{"id_order":"0006"}]');

var old_storage = JSON.parse('[{"id_order":"0001"},{"id_order":"0002"},{"id_order":"0003"},{"id_order":"0004"},{"id_order":"0005"}]');

using filter:

var diff = new_storage
.filter(x => {if(!(old_storage.filter(y => y.id_order==x.id_order)).length){return x}})
    .concat(old_storage
    .filter(x => {if(!(new_storage.filter(y => y.id_order==x.id_order)).length){return x}})
                       ) 

console.log(JSON.stringify(diff))

result difference in two arrays

[{"id_order":"0006"},{"id_order":"0001"},{"id_order":"0002"},{"id_order":"0005"}]
Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
uscamayta
  • 1
  • 1
0
const difference = function (baseArray, arrayToCampare, callback = (a, b) => a!== b) {
  if (!(arrayToCampare instanceof Array)) {
    return baseArray;
  }
  return baseArray.filter(baseEl =>
    arrayToCampare.every(compareEl => callback(baseEl, compareEl)));
}
Yaremenko Andrii
  • 759
  • 10
  • 9
  • You should never extend a native object this way. If the standard introduces `difference` in a future version and this function then has a different function signature then yours, it will break your code or foreign libraries you use. – t.niese Jul 25 '17 at 11:29
0
function array_diff(a, b) {

    let array = [];
    for(let i = 0; i <a.length; i++) {
        let k = 0;
        for( let j = 0; j < b.length; j++) {
            if(a[i]!==b[j]) {
                k++;
            }
            if(k===b.length) {
                array = array.concat(a[i]);
            }
        }

        if(b.length ===0) {
            array = array.concat(a[i]);
        }
    }
    return array;
}
  • 2
    Code with no explanation is not very helpful. SO is not a "write some code for me" resource, answers should provide information, not just copy/paste code snippets. – Adrian Jun 02 '17 at 21:15
0

Here is how I get two arrays difference. Pure and clean.

It will return a object that contain [add list] and [remove list].

  function getDiff(past, now) {
        let ret = { add: [], remove: [] };
        for (var i = 0; i < now.length; i++) {
          if (past.indexOf(now[i]) < 0)
            ret['add'].push(now[i]);
        }
        for (var i = 0; i < past.length; i++) {
          if (now.indexOf(past[i]) < 0)
            ret['remove'].push(past[i]);
        }
        return ret;
      }
rosethorn999
  • 81
  • 1
  • 8
0

You can use a common object and count the frequency of each value in the first array. For the second array, decrement the value in the common object. Then iterate through all keys and add all the keys whose values is more than 1.

const difference = (a1, a2) => {
  var obj = {};
  a1.forEach(v => obj[v] = (obj[v] || 0) + 1);
  a2.forEach(v => obj[v] = (obj[v] || 0) - 1);
  return Object
      .keys(obj)
      .reduce((r,k) => {
        if(obj[k] > 0)
          r = r.concat(Array.from({length: obj[k]}).fill(k));
        return r;
      },[]);
};
const result = difference(['a', 'a', 'b', 'c', 'd'], ['a', 'b']);
console.log(result);
Hassan Imam
  • 21,956
  • 5
  • 41
  • 51
0

**This returns an array of unique values, or an array of duplicates, or an array of non-duplicates (difference) for any 2 arrays based on the 'type' argument. **

let json1 = ['one', 'two']
let json2 = ['one', 'two', 'three', 'four']

function uniq_n_shit (arr1, arr2, type) {

  let concat = arr1.concat(arr2)
  let set = [...new Set(concat)]

  if (!type || type === 'uniq' || type === 'unique') {

    return set

  } else if (type === 'duplicate') {

    concat = arr1.concat(arr2)
    return concat.filter(function (obj, index, self) {
      return index !== self.indexOf(obj)
    })

  } else if (type === 'not_duplicate') {

    let duplicates = concat.filter(function (obj, index, self) {
      return index !== self.indexOf(obj)
    })

    for (let r = 0; r < duplicates.length; r++) {
      let i = set.indexOf(duplicates[r]);
      if(i !== -1) {
        set.splice(i, 1);
      }
    }

    return set

  }
}

console.log(uniq_n_shit(json1, json2, null)) // => [ 'one', 'two', 'three', 'four' ]
console.log(uniq_n_shit(json1, json2, 'uniq')) // => [ 'one', 'two', 'three', 'four' ]
console.log(uniq_n_shit(json1, json2, 'duplicate')) // => [ 'one', 'two' ]
console.log(uniq_n_shit(json1, json2, 'not_duplicate')) // => [ 'three', 'four' ]
Flavio
  • 506
  • 4
  • 9
0

It feels easier to process this as partial functions to me. Quite surprised not to see a functional programming solution, here is mine in ES6:

const arrayDiff = (a, b) => {
  return diff(b)(a);
}

const contains = (needle) => (array) => {
  for (let i=0; i < array.length; i++) {
    if (array[i] == needle) return true;
  }

  return false;
}

const diff = (compare) => {
    return (array) => array.filter((elem) => !contains(elem)(compare))
}
Decebal
  • 1,376
  • 1
  • 21
  • 36
0

if you don't care about original arrays and have no problem to edit them then this is quicker algorithm:

let iterator = arrayA.values()
let result = []
for (entryA of iterator) {
    if (!arrayB.includes(entryA)) {
        result.push(entryA)
    } else {
        arrayB.splice(arrayB.indexOf(entryA), 1) 
    }
}

result.push(...arrayB)
return result

Rohanil
  • 1,717
  • 5
  • 22
  • 47
0

Based on Thinker's answer, but allows duplicates.

The map increments map values as they appear, and decrements them if they are in the other array.

Any leftover will be included in the difference.

function diff(curr, prev) {
  let a = curr.split('').sort(), b = prev.split('').sort(), c = arrDiff(a, b);
  console.log(JSON.stringify(a), '-', JSON.stringify(b), '=', JSON.stringify(c));
  return c;
}

function arrDiff(larger, smaller) {
  var entries = {};
  for (var i = 0; i < larger.length; i++) {
    entries[larger[i]] = (entries[larger[i]] || 0) + 1;
  }
  for (var i = 0; i < smaller.length; i++) {
    if (entries[smaller[i]]) {
      entries[smaller[i]] -= 1;
    } else {
      entries[smaller[i]] = (entries[smaller[i]] || 0) + 1;
    }
  }
  return Object.keys(entries).sort().reduce((diff, key) => {
    if (entries[key] > 0) {
      for (var i = 0; i < entries[key]; i++) {
        diff.push(key);
      }
    }
    return diff;
  }, []);
}

// Smaller is a subset of Larger
console.log('Result:', JSON.stringify(diff('ENLIGHTEN', 'LENGTHEN'))); // [ I ]
console.log('Result:', JSON.stringify(diff('STRENGTH', 'TENTHS')));    // [ G, R ]

// Both have a unique value
console.log('Result:', JSON.stringify(diff('BUBBLE', 'RUBBLE')));      // [ B, R ]
.as-console-wrapper { top: 0; max-height: 100% !important; }
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
0

Here is a slightly modified version that uses an Object to store the hashes can handle numbers as well as strings in arrays.

function arrDiff(a, b) {
  const hash = {};
  a.forEach(n => { hash[n] = n; });
  b.forEach(n => {
    if (hash[n]) {
      delete hash[n];
    } else {
      hash[n] = n;
    }
  });
  return Object.values(hash);
}
Joe Seifi
  • 1,557
  • 1
  • 12
  • 15
0
var compare = array1.length > array2.length ? array1 : array2;
var compareWith = array1.length > array2.length ? array2 : array1;
var uniqueValues = compareWith.filter(function(value){
                    if(compare.indexOf(vakye) == -1)
                       return true;
                   });

This will both check which one is the larger one among the arrays and then will do the comparison.

Vishal
  • 816
  • 11
  • 19
0
function diffArray(newArr, oldArr) {
    var newSet = new Set(newArr)
    var diff = []
    oldArr.forEach((a) => {
        if(!newSet.delete(a))diff.push(a)
    })
    return diff.concat(Array.from(newSet)) 
}
Pram
  • 2,383
  • 2
  • 19
  • 21
0

In response to post (Comparing two arrays containing integers JavaScript) by adaen that was closed:

A couple of options:

  1. SIMPLEST -> You can add all the entries of the second array to a hashmap. Then iterate over the entries in the first array and log the ones that don't exist in the hashmap.
const arrOne = [2,3,10,7,9,15,7,15,21,1];
const arrTwo = [3,15,1,2,21];

const hash = {};

arrTwo.forEach(a => hash[a]++);
arrOne.filter(a => typeof hash[a] === 'undefined').forEach(a => console.log(a));
  1. Your other option would be to sort both arrays. Then iterate over the second array. Inside it, iterate over the first array. As you encounter entries in the first array that are less than the next entry in the second array but not equal to it, you log them out.
const arrOne = [2,3,10,7,9,15,7,15,21,1].sort((a,b)=>a-b);
const arrTwo = [3,15,1,2,21].sort((a,b)=>a-b);

var i1 = 0;
for(var i2 = 0; i2 < arrTwo.length; i2++) {
  while(arrOne[i1] < arrTwo[i2+1]) {
    if(arrOne[i1] != arrTwo[i2]) {
      console.log(arrOne[i1]);
    }
    i1++;
  }
}
cbush06
  • 46
  • 2
0
function array_diff(array1, array2) {
   let returnArray = [];
   $.each(array1, function(index, value) {
     let findStatus = false;
     if (Array.isArray(array2)) {
       $.each(array2, function(index2, value2) {
         if (value == value2) findStatus = true;
       });
     } else {
       if (value == array2) {
         findStatus = true;
       }
     }

     if (findStatus == false) {
       returnArray.push(value);
     }
   });
   return returnArray;
}
Muazzez
  • 13
  • 3
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Apr 26 '22 at 06:58
0
function diffArray(arr1, arr2) {
  const newArr = [];

// arr1 match to arr2
arr1.map((item)=>{
if(arr2.indexOf(item)<0){
  console.log(item)
  newArr.push(item)
}  
})

// arr2 match to arr1
arr2.map((item)=>{
if(arr1.indexOf(item)<0){
  newArr.push(item)
}
})

  return newArr; 
}

diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5])

Output :: [ 4 ]

0

Here is the faster approach by using map

const arr1 = ['a','b','c','d'];
const arr2 = ['a','b','c']
let table = {}
arr1.forEach(v=>{table[v]=false})
arr2.forEach(v=>{
    if(table[v]===false) table[v] = true
    else table[v] = false
})
const diff = Object.keys(table).filter(v=>table[v]==false)
時雨初
  • 435
  • 4
  • 4
-1

I fall into this question, which was to get the difference of two simple arrays

var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];

// need ["c", "d"]

and I don't see why not go with the basic for loops :

for(var i=0; i < a1.length; i++) {
  for(var j=0; j < a2.length; j++) {
    if(a1[i] == a2[j]) {
      a2.splice(j, 1);
    }
  }
}

which would return the needed ["c", "d"]

[edit] proposed right above, seen to late.

Anyway, any good reason to avoid this simple solution ?

jndvdcn
  • 105
  • 8
-3

Cast to string object type:

[1, 1].toString() === [1, 1].toString(); // true
spenibus
  • 4,339
  • 11
  • 26
  • 35