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"]
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"]
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"));
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 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 Array.prototype.includes()
(ES2016/ ES7) comes in handy here.
let intersection = arr1.filter(x => arr2.includes(x));
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]
(Values in just A.)
let difference = arr1.filter(x => !arr2.includes(x));
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]
let symDifference = arr1.filter(x => !arr2.includes(x))
.concat(arr2.filter(x => !arr1.includes(x)));
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]
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. –
Churchwell Set
, values have to be unique, no? –
Freesia [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 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 Array.prototype.diff = arr1.filter(x => arr2.includes(x)); ^ ReferenceError: arr1 is not defined
–
Crane 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 arr2_copy = [...arr2]; arr1.filter((elem) => { if (arr2_copy.includes(elem)) { arr2_copy.pop(elem); return false; } else { return true; }});
–
Gorlin 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 [1, 2, 3].diff([3]).diff([2])
–
Gorlin 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.
[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 [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 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 ruby
code, the Array.diff is builtin: array1 - array2
. –
Killy diff
. What you propose can be achieved like this: [...arr1.diff(arr2), ...arr2.diff(arr1)] –
Lullaby 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"));
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 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 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
{a: 1} != {a: 1}
) (proof) –
Hunk .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 old_array
is the one which has more values than new_array
, else, it won't return the diff... which sucks. –
Expansion O(m x n)
, where m
is the length of old_array
ad n
the length of new_array
? –
Since Ext.Array.difference(array1, array2)
. –
Unmake 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]);
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'];
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;
}
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;
}
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.
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));
}
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.)
Set
to solve this problem is amazing. –
Crosswise A cleaner approach in ES6 is the following solution.
var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];
a2.filter(d => !a1.includes(d)) // gives ["c", "d"]
a2.filter(d => a1.includes(d)) // gives ["a", "b"]
[ ...a2.filter(d => !a1.includes(d)),
...a1.filter(d => !a2.includes(d)) ]
a1 = ['a', 'b', 'e']
: e won't be extracted. –
Vinegarish To get the symmetric difference you need to compare the arrays in both ways (or in all the ways in case of multiple arrays)
// 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));
}));
}
// 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);
}));
}
// 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"]
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}]
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}
Set
function without having to get everything else... –
Denbighshire difference
method. –
Mayemayeda 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
));
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 })
);
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" ]
.
b.filter(x => !a.indexOf(x)))
–
Crane 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 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 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 a
was a Set, because then it would have to be converted to an array to run filter on it. –
Jaimeejaimes 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().
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;
});
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]
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.
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) );
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!
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.
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']
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 ]
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);
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)))
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]
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 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)
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
const a1 = ['a', 'b', 'c', 'd'];
const a2 = ['a', 'b'];
const diffArr = a1.filter(o => !a2.includes(o));
console.log(diffArr);
Output:
[ 'c', 'd' ]
!a2.includes(o)
. I edited your answer if you don't mind... –
Eisk 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
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}
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"]
filter
)fn
callback parameter that lets you specify how to compare array itemsfunction 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(', ')
);
length
values. It's already plain property. jsperf.com/array-length-caching –
Binturong 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};
}
var
all over makes me feel a bit 🤮 –
Amblyoscope 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]
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;
}
//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
}
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));
}
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
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])
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);
var first = [ 4, 5, 6 ];
and var second = [ 1, 2, 3, 4, 5, 6 ];
–
Aplite 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)
const dbData = [{name:'ally'},
{name:'James'}]
const localData = [{name:'James'}]
const diff = dbData.filter(a =>!localData.some(b => { return a.name === b.name}))
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.
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.
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);
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;
}
}
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);
}
}
}
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!"
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 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]
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.
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;
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' ]
// }
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.
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.
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])}
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;
}
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; });
};
}
CoffeeScript version:
diff = (val for val in array1 when val not in array2)
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' ]
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])
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
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)));
}
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;
}
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:
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;
};
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]
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;
}
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;
});
};
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);
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}]
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);
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]);
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;
});
}
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"}]
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)));
}
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 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;
}
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;
}
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);
**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' ]
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))
}
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
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; }
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);
}
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.
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))
}
In response to post (Comparing two arrays containing integers JavaScript) by adaen that was closed:
A couple of options:
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));
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++;
}
}
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 ]
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)
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 ?
Cast to string object type:
[1, 1].toString() === [1, 1].toString(); // true
© 2022 - 2024 — McMap. All rights reserved.
O(a1.length x log(a2.length))
- is this performance possible in JavaScript? – Since