How to get the difference between two arrays in JavaScript?
Asked Answered
C

84

1351

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"]
Cosgrave answered 27/7, 2009 at 10:38 Comment(6)
Symmetric or non-symmetric?Karlkarla
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 answerYmir
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?Since
Check my library, it can help you with this, @netilon/differify is one of the fastest diff libraries for object/array comparison: npmjs.com/package/@netilon/differifyMultipara
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.Renfrew
you can use fitler, check my answer https://mcmap.net/q/45353/-how-to-get-the-difference-between-two-arrays-in-javascriptNazi
H
382

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"));
Hysteresis answered 27/7, 2009 at 11:20 Comment(17)
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.Siemens
Just to be clear, this implements the symmetric difference of a1 and a2, unlike the other answers posted here.Feeding
This is still relevant if you have to support IE8, which does not have filterInherence
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?Domineering
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.Fda
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'].Cyprinid
I ran this into an online compiler. This converts numbers in arrays to strings when it returns them.Dewdrop
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.Circumcise
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; }Limpet
User @JoLiss had an almost identical solution, by the way.Limpet
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.Unseasonable
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.Phototelegraphy
@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.Garman
Yeah man, this is the year 2020. You should update the answer with the modern approach: filter and includes.Tank
pHp has this in the standard library :-)Carlton
Well there are some errorneous claims about the algorithm speed. Check out my answer comparing all three methods with jsPerf.Outage
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.Miry
G
2932

Array.prototype.includes() (ES2016/ ES7) comes in handy here.


Intersection

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

Intersection Venn Diagram

Yields values which are present in both arr1 and arr2.

  • [1,2,3] and [2,3] will yield [2,3]
  • [1,2,3] and [2,3,5] will also yield [2,3]

Difference

(Values in just A.)

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

Right difference Venn Diagram

Yields values that are present in just arr1.

  • [1,2,3] and [2,3] will yield [1]
  • [1,2,3] and [2,3,5] will also yield [1]

Symmetric Difference

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

Symmetric difference Venn Diagram

Yields values that are only in arr1 or arr2, but not both ("exclusive or").

This is what you get if you take the difference of both arrays with each other, and combine the two results (You get an array containing all the elements of arr1 that are not in arr2 and vice-versa).

  • [1,2,3] and [2,3] will yield [1]
  • [1,2,3] and [2,3,5] will yield [1,5]

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

Array.prototype.diff = function(arr2) { 
  return this.filter(x => !arr2.includes(x)); 
}
[1, 2, 3].diff([2, 3]) // [1]
Gorlin answered 9/10, 2015 at 9:33 Comment(19)
Computing the Array difference is a so called set operation, because property lookup is the very own job of Sets, which are orders of magnitude faster then indexOf/includes. Simply put, your solution is very inefficient and rather slow.Churchwell
@ftor but with Set, values have to be unique, no?Freesia
@Freesia 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.Gorlin
@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 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!Freesia
Fantastic explanation! It reminds me of Jeff Atwood's SQL join post: blog.codinghorror.com/a-visual-explanation-of-sql-joinsMange
Isn't Array.includes() ES7 feature instead of ES6? (1) (2) — and to continue, with ES6 you could use Array.some() e.g. let intersection = aArray.filter(a => bArray.some(b => a === b)), no?Foxed
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 definedCrane
@Crane arr1 and arr2 are the arrays you're performing the operation with.Gorlin
@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.Mccomas
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 bGorlin
great answer, but should rename variables arr1/arr2 to arrA/arrB to match the diagramsBeluga
does not work here [4,9,5] [9,4,9,8,4]Hanus
@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; }});Gorlin
This answer should be pinned to the homepage as a guideline as for how to write an answer on StackExchange networkVoss
See also Nina Scholz's answer. 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)...Roubaix
jsbench.me/oal76coxx0/2Roubaix
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!Polak
What should I modify to make it for many arrays?Maura
@MenaiAlaEddine-Aladdin, since the result of the operation is an array itself, if you added it to the prototype you can just chain calls like so: [1, 2, 3].diff([3]).diff([2])Gorlin
S
959

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.

Siemens answered 26/10, 2010 at 18:34 Comment(20)
Also, you may find useful editing tutorialAlderman
The only browser that matters that doesn't support filter and indexOf is IE8. IE9 does support them both. So it's not wrong.Indulgence
ie7 and ie8 are still (unfortunately) very relevant, however you can find polyfill code for both functions on the MDN site: developer.mozilla.org/en/JavaScript/Reference/Global_Objects/… developer.mozilla.org/en/JavaScript/Reference/Global_Objects/… Load in the code listed under "compatability" via an IE conditional & BOOM. Ie7/8 are supported.Burdick
you could also use the filter function provided by jQuery.Toothlike
This solution has a run time of O(n^2) a linear solution would be far more efficient.Kimbro
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.Iggy
Beware, this implementation will not work for arrays of objects. See https://mcmap.net/q/46387/-how-to-use-underscore-39-s-quot-intersection-quot-on-objects/14731 for more information.Apomixis
@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.Bascinet
@Iggy Good point. It seems like the original poster was asking for the symmetric difference.Stacystadholder
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)Croaky
Note: this doesn't return the same results if you flip the arrays.Sparing
@Kimbro : a O(n*log(n)) solution would be to sort the 2 arrays and then do a linear merge. Can we better that ?Roxannroxanna
@jholloman: yes indeed, and an O(1) would indeed be even more efficient!Wheal
For me the biggest downside of this is that it modifies the prototype of a built-in object. I prefer to avoid that.Paramour
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].Mushy
@StijndeWitt If u dont like prototype... just use it as a function or in-line and not add as prototype?Darleen
@Darleen 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]Tot
While only an example, I would strongly recommend against the use of monkey-patching anything due to stuff like this: developers.google.com/web/updates/2018/03/smooshgate. Nobody wants a second "smooshgate" I'm sure :)Unthankful
Amazing. On ruby code, the Array.diff is builtin: array1 - array2.Killy
@MichaelPlautz that depends on how you define the diff. What you propose can be achieved like this: [...arr1.diff(arr2), ...arr2.diff(arr1)]Lullaby
H
382

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"));
Hysteresis answered 27/7, 2009 at 11:20 Comment(17)
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.Siemens
Just to be clear, this implements the symmetric difference of a1 and a2, unlike the other answers posted here.Feeding
This is still relevant if you have to support IE8, which does not have filterInherence
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?Domineering
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.Fda
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'].Cyprinid
I ran this into an online compiler. This converts numbers in arrays to strings when it returns them.Dewdrop
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.Circumcise
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; }Limpet
User @JoLiss had an almost identical solution, by the way.Limpet
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.Unseasonable
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.Phototelegraphy
@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.Garman
Yeah man, this is the year 2020. You should update the answer with the modern approach: filter and includes.Tank
pHp has this in the standard library :-)Carlton
Well there are some errorneous claims about the algorithm speed. Check out my answer comparing all three methods with jsPerf.Outage
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.Miry
S
314

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

Subjacent answered 13/3, 2013 at 12:57 Comment(10)
@Batman Yes, but only if they are references to the same object ({a: 1} != {a: 1}) (proof)Hunk
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.Cowpea
Is this a trick? The doc considers this method as part of the 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.Files
@Files 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.Subjacent
Any chance to adapt this for Angular2 / typescript?Mchugh
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.Expansion
@Expansion Sounds like you are after a symmetric differenceSubjacent
I don't know, I didn't study computer science. I know I'm after getting the diff of 2 arrays, is allExpansion
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?Since
For ExtJS use Ext.Array.difference(array1, array2).Unmake
E
178

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]);
Econometrics answered 5/7, 2012 at 22:44 Comment(6)
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.Econometrics
Beware, this implementation will not work for arrays of objects. See https://mcmap.net/q/46387/-how-to-use-underscore-39-s-quot-intersection-quot-on-objects/14731 for more information.Apomixis
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().Econometrics
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.Jodhpur
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 diffHudgins
Order always matters when calculating difference of 2 collections ... it's a question of which side of the venn diagram you want.Econometrics
K
99

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

Kristine answered 17/5, 2015 at 16:1 Comment(2)
Thank. you saved my day. I had to compare a 300K arrays, and your "Set" solution worked perfectly. This should be the accepted answer.Inquest
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.Crosswise
H
78

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)) ]
Harrisharrisburg answered 26/1, 2020 at 19:41 Comment(3)
It works only in one direction. Now imagine that a1 = ['a', 'b', 'e'] : e won't be extracted.Vinegarish
yes, that's how the difference in set theory works. (a2 -a1) what you are looking for is (a2-a1) + (a1-a2)Harrisharrisburg
@Vinegarish I believe this is what you are looking for [...a2.filter(d => !a1.includes(d)) , ...(a1.filter(d => !a2.includes(d)))]Harrisharrisburg
Q
70

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}]
Qua answered 20/9, 2018 at 17:4 Comment(0)
B
54

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}
Baseman answered 27/7, 2009 at 10:43 Comment(5)
That looks like a nice library! What a shame that you can't download just the Set function without having to get everything else...Denbighshire
@Denbighshire I believe you can download it all, and just include just the set.js fileBaseman
Set is implemented in google closure as well. closure-library.googlecode.com/svn/docs/…Deme
Wow, it's been 1 year? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Disentail
@Disentail Unfortunately the built-in ES Set doesn't have this handy difference method.Mayemayeda
D
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 })
  );
Dysphagia answered 27/9, 2021 at 17:22 Comment(2)
Anyone have the TS version of uniqueBy?Wycoff
@Wycoff it's readyDysphagia
Y
34

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" ].

Ymir answered 17/1, 2015 at 7:15 Comment(8)
Just curious how is that any different than doing b.filter(x => !a.indexOf(x)))Crane
@Crane 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.Ymir
What about comparing an attribute of a list of objects? Is that possible using this solution?Crane
@Crane what do you mean by comparing an attribute of a list of objects?Ymir
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.Then
@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));Benignity
@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.Jaimeejaimes
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.Jenicejeniece
Y
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().

Yseulte answered 30/6, 2015 at 14:33 Comment(1)
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 EinsteinJudie
V
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;
});
Villa answered 21/11, 2011 at 11:26 Comment(0)
A
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]
Affection answered 1/11, 2016 at 21:47 Comment(0)
C
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.

Churchwell answered 11/10, 2016 at 16:0 Comment(0)
S
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']
Sigfrid answered 15/5, 2012 at 15:22 Comment(3)
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.Kimbro
@Kimbro I respectfully disagree. Now that we can control enumerability for any property, presumably you should be including any property that you get during enumeration.Emendate
@Emendate 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.Kimbro
J
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 ]

Jeffcott answered 20/9, 2012 at 18:27 Comment(0)
G
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);
Grunter answered 11/4, 2017 at 21:56 Comment(0)
T
8

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)))
Telling answered 15/10, 2021 at 9:1 Comment(1)
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 VikasPittsburgh
B
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]
Bulldoze answered 7/7, 2015 at 14:55 Comment(1)
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.Herbart
E
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)

Eben answered 5/8, 2010 at 21:10 Comment(2)
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!Siemens
You don't need to define the contains() function. JS includes() does the same thing.Kilogram
W
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

Whist answered 5/5, 2016 at 14:24 Comment(0)
N
6
const a1 = ['a', 'b', 'c', 'd'];
const a2 = ['a', 'b'];

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

console.log(diffArr);

Output:

[ 'c', 'd' ]
Nazi answered 4/11, 2022 at 12:58 Comment(2)
this gets similar only, not diff. it should be !a2.includes(o). I edited your answer if you don't mind...Eisk
the output should be ['c', 'd'] instead of ['a', 'b']Brei
J
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

Jenicejeniece answered 3/2, 2021 at 21:40 Comment(0)
R
5

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}
Raskin answered 20/5, 2021 at 10:39 Comment(0)
E
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"]
Emendate answered 25/1, 2011 at 18:21 Comment(0)
I
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(', ')
);
Insure answered 17/9, 2014 at 19:57 Comment(2)
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.Humiliate
No reason to cache length values. It's already plain property. jsperf.com/array-length-cachingBinturong
A
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}; 
}
Amblyoscope answered 13/8, 2010 at 12:7 Comment(3)
Thank you very much, your code helped me a lot! @Ian GraingerCalva
@Calva NP! Man, this is old, now. Seeing var all over makes me feel a bit 🤮Amblyoscope
lol @Ian Grainger Surely the experience you have now exceeds your own expectations of those yesterdays....Calva
F
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]
Fact answered 27/9, 2012 at 8:55 Comment(0)
F
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;
}
Fugger answered 1/8, 2015 at 10:33 Comment(0)
F
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
}
Forerunner answered 4/8, 2017 at 20:54 Comment(0)
E
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));
}
Epsilon answered 17/5, 2018 at 0:7 Comment(0)
A
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

Autogenesis answered 17/5, 2019 at 12:15 Comment(0)
B
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])
Biltong answered 12/2, 2020 at 11:40 Comment(0)
T
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);
Trimurti answered 24/5, 2021 at 5:41 Comment(1)
This is not correct. Try var first = [ 4, 5, 6 ]; and var second = [ 1, 2, 3, 4, 5, 6 ];Aplite
S
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)
Shaunshauna answered 26/5, 2021 at 9:30 Comment(0)
S
3
const dbData = [{name:'ally'}, 
{name:'James'}]
const localData = [{name:'James'}] 

const diff = dbData.filter(a =>!localData.some(b => { return a.name === b.name}))
Selfcontained answered 2/11, 2022 at 9:21 Comment(1)
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: stackoverflow.com/help/how-to-answer . Good luckOpe
B
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.

Bainter answered 16/7, 2011 at 4:22 Comment(0)
D
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.

Diarmid answered 18/4, 2012 at 6:43 Comment(1)
This still fails for an array of objects. var a = [{a: 1}], b = [{b: 2}] arr_diff(a,b) == [].Orford
P
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);
Plowboy answered 15/9, 2013 at 17:6 Comment(1)
First example which works for string arrays like a charm. Thank you @PlowboyAustralian
L
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;
    }
}   
Landloper answered 30/1, 2014 at 17:19 Comment(0)
C
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);
    }
  }
}
Culhert answered 21/8, 2014 at 7:29 Comment(0)
C
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!"
Crossbow answered 11/10, 2015 at 7:23 Comment(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.Herbart
@Herbart 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 ;)Crossbow
@Crossbow Well, as the saying goes, a smart developer can fix problems that a wise developer knows to avoid in the first place.Wilscam
K
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]
Keeleykeelhaul answered 8/2, 2016 at 6:57 Comment(1)
this is symmetric difference.Druid
T
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.

Thomasinethomason answered 25/10, 2017 at 9:6 Comment(0)
U
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;
Unvoice answered 16/12, 2018 at 19:45 Comment(0)
M
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' ] 
// }
Morgun answered 12/6, 2019 at 21:1 Comment(0)
O
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.

Oxygenate answered 27/7, 2009 at 11:11 Comment(0)
K
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.

Kherson answered 20/7, 2011 at 12:20 Comment(1)
It does not work for some times, can you tell me "If no more than say 1000 elements try this..." ur statement meaning..Cerda
K
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])}
Kherson answered 20/7, 2011 at 16:33 Comment(0)
B
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;
  }
Bearskin answered 29/5, 2013 at 10:25 Comment(0)
P
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; });
    }; 
}
Pediment answered 25/6, 2013 at 13:38 Comment(1)
@DotNetWise This is the eqvivalent of Joshaven's answer above with jQuery methods. Did you downvote him as well?Pediment
E
1

CoffeeScript version:

diff = (val for val in array1 when val not in array2)
Equitable answered 20/3, 2015 at 16:33 Comment(0)
S
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' ]
Stinky answered 10/4, 2018 at 17:57 Comment(0)
L
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])
Latona answered 7/2, 2020 at 10:44 Comment(0)
I
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

Illogic answered 12/7, 2020 at 12:14 Comment(0)
R
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)));
    }
Retinoscopy answered 16/1, 2021 at 15:44 Comment(0)
L
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;
}
Looney answered 27/7, 2009 at 10:39 Comment(1)
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.If
S
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;

};
Solemn answered 15/5, 2012 at 14:58 Comment(0)
A
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]
Alejandraalejandrina answered 14/1, 2014 at 22:2 Comment(0)
R
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;
}
Retrospect answered 7/3, 2014 at 19:9 Comment(1)
Too much you trimmed :)Spectator
M
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;
    });
};
Merideth answered 27/10, 2014 at 16:12 Comment(0)
U
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);
Unemployed answered 14/12, 2014 at 2:26 Comment(0)
C
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}]
Crane answered 15/6, 2015 at 8:19 Comment(0)
R
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);
Rileyrilievo answered 16/1, 2016 at 15:5 Comment(0)
S
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]);
Sacrarium answered 24/5, 2016 at 7:33 Comment(1)
Please check this URL it will be handy to lift your content qualify upBarrelchested
C
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;
    });
}
Cantata answered 6/9, 2016 at 14:43 Comment(0)
C
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"}]
Cracker answered 13/10, 2016 at 23:41 Comment(0)
R
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)));
}
Rode answered 12/1, 2017 at 14:6 Comment(1)
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.Herbart
M
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;
}
Momus answered 2/6, 2017 at 20:54 Comment(1)
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.Dunn
C
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;
      }
Cabstand answered 15/8, 2017 at 7:5 Comment(0)
A
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);
Angola answered 26/1, 2018 at 16:48 Comment(0)
S
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' ]
Stinky answered 8/6, 2018 at 7:31 Comment(0)
M
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))
}
Mauromaurois answered 15/12, 2018 at 15:49 Comment(0)
D
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

Dedrick answered 30/7, 2019 at 11:57 Comment(0)
D
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; }
Dulcimer answered 17/12, 2019 at 13:57 Comment(0)
I
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);
}
Insolvable answered 10/9, 2020 at 4:52 Comment(0)
C
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.

Carbolize answered 7/11, 2020 at 18:54 Comment(0)
S
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)) 
}
Shaunteshave answered 8/12, 2020 at 6:6 Comment(0)
S
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++;
  }
}
Specie answered 2/9, 2021 at 17:17 Comment(0)
M
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 ]

Mancunian answered 24/7, 2022 at 1:36 Comment(0)
I
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)
Injured answered 21/12, 2022 at 16:13 Comment(0)
A
-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 ?

Artillery answered 14/6, 2013 at 17:54 Comment(0)
R
-3

Cast to string object type:

[1, 1].toString() === [1, 1].toString(); // true
Randall answered 4/10, 2015 at 10:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.