Related
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"]
There is a better way using ES7:
Intersection
let intersection = arr1.filter(x => arr2.includes(x));
For [1,2,3] [2,3] it will yield [2,3]. On the other hand, for [1,2,3] [2,3,5] will return the same thing.
Difference
let difference = arr1.filter(x => !arr2.includes(x));
For [1,2,3] [2,3] it will yield [1]. On the other hand, for [1,2,3] [2,3,5] will return the same thing.
For a symmetric difference, you can do:
let difference = arr1
.filter(x => !arr2.includes(x))
.concat(arr2.filter(x => !arr1.includes(x)));
This way, you will get an array containing all the elements of arr1 that are not in arr2 and vice-versa
As #Joshaven Potter pointed out on his answer, you can add this to Array.prototype so it can be used like this:
Array.prototype.diff = function(arr2) { return this.filter(x => !arr2.includes(x)); }
[1, 2, 3].diff([2, 3])
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.
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"));
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
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]);
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'];
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;
}
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.)
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)) ]
To get the symmetric difference you need to compare the arrays in both ways (or in all the ways in case of multiple arrays)
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}]
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}
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 })
);
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().
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" ].
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]
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.
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);
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]
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
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)))
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"]
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(', ')
);
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}
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};
}
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
}
I have seen many question/answer subject to merge two array by alternating Values. they are working like this:
let array1 = ["a", "b", "c", "d"];
let array2 = [1, 2];
let outcome = ["a",1 ,"b", 2, "c", "d"]
but i want output to be more efficient with even distribution of value based on array size.
expected outcome = ["a","b", 1, "c", "d", 2]
other scenario
let array2 = [1];
expected outcome = ["a","b", 1, "c", "d"]
what should be the best way to achieve this sort of merging?
Find the ratio of the two arrays' lengths, longest.length/shortest.length and then take that many from the longest for every one in the shortest.
let array1 = ["a", "b", "c", "d", "e"];
let array2 = [1, 2];
const evenDistribute = (array1, array2) => {
const longest = array1.length > array2.length ? array1 : array2;
const shortest = array1.length > array2.length ? array2 : array1;
const ratio = Math.floor(longest.length / shortest.length);
const results = [];
for (let i = 0; i < shortest.length; i++) {
for (let j = 0; j < ratio; j++) {
results.push(longest[i * ratio + j]);
}
results.push(shortest[i]);
}
// Grab any that are left over
for (let i = longest.length - (longest.length % shortest.length); i < longest.length; i++) {
results.push(longest[i]);
}
return results;
}
console.log(evenDistribute(array1, array2));
The idea is to find out per how many items of the long array you will have to mix an item from the short array. The code below is to demonstrate the concept. Maybe you will have to adjust it a little bit for all edge scenarios.
let array1 = ["a", "b", "c", "d"];
let array2 = [1, 2];
//Get the long and short arrays and calc the length factor
var [longArray, shortArray] = array1.length >= array2.length ? [array1, array2] : [array2, array1];
let lengthFactor = longArray.length / shortArray.length;
var c = 0
let smallIdx = 0;
let result = longArray.flatMap(item => {
c++;
if (c % lengthFactor === 0) {
return [item, shortArray[smallIdx++]]
}
else
return [item];
})
console.log(result);
You could get the interval for distribution. Then loop through the second array and use splice to update the specific indices of the first array.
function distribute(original, replace) {
const interval = Math.ceil(original.length / (replace.length + 1));
replace.forEach((r, i) => original.splice(interval * (i + 1) + i, 0, r))
console.log(...original)
}
distribute(["a", "b", "c", "d"], [1])
distribute(["a", "b", "c", "d"], [1, 2])
distribute(["a", "b", "c", "d"], [1, 2, 3])
distribute(["a", "b", "c", "d", "e", "f"], [1, 2])
distribute(["a", "b", "c", "d", "e", "f"], [1, 2, 3])
This function was influenced by adiga's answer but handles the distribution a little better by calculating the insert index based on a decimal interval instead of Math.ceil.
It also avoids mutating the input arrays by creating a copy of the long array before inserting the short array's data.
If you find any cases that it doesn't cover let me know :)
function mergeAndDistributeArrays(array1, array2) {
// Find the long/short arrays based on length
const [long, short] =
array1.length >= array2.length ? [array1, array2] : [array2, array1];
// Calculate the interval
const interval = long.length / (short.length + 1);
// Copy the long array so we don't mutate the input arrays
const merged = [...long];
// Iterate the short array and insert the values into the long array
short.forEach((value, index) => {
// Calculate the insert index based on the interval and the current index
const insertAt = Math.ceil(interval * (index + 1));
// Insert the value
merged.splice(insertAt + index, 0, value);
});
return merged;
}
console.log(
mergeAndDistributeArrays(
[1,2,3],
['a','b','c','d','e','f','g','h','i']
)
);
let array1 = ['a', 'b', 'c', 'd', 'e'];
let array2 = [1, 2];
function merge(arr1, arr2) {
let newArr1 = JSON.parse(JSON.stringify(arr1));
let newArr2 = JSON.parse(JSON.stringify(arr2));
[newArr1, newArr2] = newArr1.length >= newArr2.length ? [newArr1, newArr2] : [newArr2, newArr1];
const interval = newArr1.length / newArr2.length;
newArr2.map((item, index) => {
newArr1.splice(interval * (index + 1), 0, item);
})
return newArr1;
}
console.log(merge(array1, array2));
const mix = (firstArray, secondArray) => {
const itrArray = firstArray.length > secondArray.length ? firstArray : secondArray;
const result = [];
for(let i=0; i<itrArray.length; i++){
firstArray[i] && result.push(firstArray[i]);
secondArray[i] && result.push(secondArray[i]);
}
return result;
}
console.log(mix([1, 2, 3], [4, 5, 6]));
// [1, 4, 2, 5, 3, 6]
console.log(mix(["h", "a", "c"], [7, 4, 17, 10, 48]));
// ["h", 7, "a", 4, "c", 17, 10, 48]
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"]
There is a better way using ES7:
Intersection
let intersection = arr1.filter(x => arr2.includes(x));
For [1,2,3] [2,3] it will yield [2,3]. On the other hand, for [1,2,3] [2,3,5] will return the same thing.
Difference
let difference = arr1.filter(x => !arr2.includes(x));
For [1,2,3] [2,3] it will yield [1]. On the other hand, for [1,2,3] [2,3,5] will return the same thing.
For a symmetric difference, you can do:
let difference = arr1
.filter(x => !arr2.includes(x))
.concat(arr2.filter(x => !arr1.includes(x)));
This way, you will get an array containing all the elements of arr1 that are not in arr2 and vice-versa
As #Joshaven Potter pointed out on his answer, you can add this to Array.prototype so it can be used like this:
Array.prototype.diff = function(arr2) { return this.filter(x => !arr2.includes(x)); }
[1, 2, 3].diff([2, 3])
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.
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"));
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
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]);
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'];
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;
}
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.)
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)) ]
To get the symmetric difference you need to compare the arrays in both ways (or in all the ways in case of multiple arrays)
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}]
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}
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 })
);
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().
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" ].
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]
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.
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);
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]
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
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)))
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"]
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(', ')
);
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}
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};
}
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
}
I have 2 arrays:
var a = [1, 2, 3]
var b = [a, b, c]
What I want to get as a result is:
[[1, a], [2, b], [3, c]]
It seems simple but I just can't figure out.
I want the result to be one array with each of the elements from the two arrays zipped together.
Use the map method:
var a = [1, 2, 3]
var b = ['a', 'b', 'c']
var c = a.map(function(e, i) {
return [e, b[i]];
});
console.log(c)
DEMO
Zip Arrays of same length:
Using Array.prototype.map()
const zip = (a, b) => a.map((k, i) => [k, b[i]]);
console.log(zip([1,2,3], ["a","b","c"]));
// [[1, "a"], [2, "b"], [3, "c"]]
Zip Arrays of different length:
Using Array.from()
const zip = (a, b) => Array.from(Array(Math.max(b.length, a.length)), (_, i) => [a[i], b[i]]);
console.log( zip([1,2,3], ["a","b","c","d"]) );
// [[1, "a"], [2, "b"], [3, "c"], [undefined, "d"]]
Using Array.prototype.fill() and Array.prototype.map()
const zip = (a, b) => Array(Math.max(b.length, a.length)).fill().map((_,i) => [a[i], b[i]]);
console.log(zip([1,2,3], ["a","b","c","d"]));
// [[1, "a"], [2, "b"], [3, "c"], [undefined, "d"]]
Zip Multiple (n) Arrays:
const zip = (...arr) => Array(Math.max(...arr.map(a => a.length))).fill().map((_,i) => arr.map(a => a[i]));
console.log(zip([1,2], [3,4], [5,6])); // [[1,3,5], [2,4,6]]
Zipping by leveraging generator functions
You can also use a generator function to zip().
const a = [1, 2, 3]
const b = ['a', 'b', 'c']
/**
* Zips any number of arrays. It will always zip() the largest array returning undefined for shorter arrays.
* #param {...Array<any>} arrays
*/
function* zip(...arrays){
const maxLength = arrays.reduce((max, curIterable) => curIterable.length > max ? curIterable.length: max, 0);
for (let i = 0; i < maxLength; i++) {
yield arrays.map(array => array[i]);
}
}
// put zipped result in an array
const result = [...zip(a, b)]
// or lazy generate the values
for (const [valA, valB] of zip(a, b)) {
console.log(`${valA}: ${valB}`);
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
The above works for any number of arrays and will zip() the longest array so undefined is returned as a value for shorter arrays.
Zipping of all Iterables
Here a function which can be used for all Iterables (e.g. Maps, Sets or your custom Iterable), not just arrays.
const a = [1, 2, 3];
const b = ["a", "b", "c"];
/**
* Zips any number of iterables. It will always zip() the largest Iterable returning undefined for shorter arrays.
* #param {...Iterable<any>} iterables
*/
function* zip(...iterables) {
// get the iterator of for each iterables
const iters = [...iterables].map((iterable) => iterable[Symbol.iterator]());
let next = iters.map((iter) => iter.next().value);
// as long as any of the iterables returns something, yield a value (zip longest)
while(anyOf(next)) {
yield next;
next = iters.map((iter) => iter.next().value);
}
function anyOf(arr){
return arr.some(v => v !== undefined);
}
}
// put zipped result in aa array
const result = [...zip(a, new Set(b))];
// or lazy generate the values
for (const [valA, valB] of zip(a, new Set(b))) {
console.log(`${valA}: ${valB}`);
}
Obviously it would also be possible to just use [...Iterable] to transform any Iterable to an array and then use the first function.
Using the reduce method:
const a = [1, 2, 3]
const b = ['a', 'b', 'c']
var c = a.reduce((acc, curr, ind) => {
acc.push([curr, b[ind]]);
return acc;
}, []);
console.log(c)
With forEach method:
const a = [1, 2, 3]
const b = ['a', 'b', 'c']
const c = [];
a.forEach((el, ind) => {
c.push([el, b[ind]])
});
console.log(c)
Providing a solution with imperative programming by a simple for loop.
This performs better when doing the zip operation on huge data sets compared to the convenient array functions like map() and forEach().
Example:
const a = [1, 2, 3];
const b = ['a', 'b', 'c'];
const result = [];
for (let i = 0; i < a.length; i++) {
result.push([a[i], b[i]]);
}
console.log(result);
And if you want a 1 line simpler solution then you can use a library like ramda which has a zip function.
Example:
const a = [1, 2, 3];
const b = ['a', 'b', 'c'];
const result = R.zip(a, b);
console.log(result);
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"]
There is a better way using ES7:
Intersection
let intersection = arr1.filter(x => arr2.includes(x));
For [1,2,3] [2,3] it will yield [2,3]. On the other hand, for [1,2,3] [2,3,5] will return the same thing.
Difference
let difference = arr1.filter(x => !arr2.includes(x));
For [1,2,3] [2,3] it will yield [1]. On the other hand, for [1,2,3] [2,3,5] will return the same thing.
For a symmetric difference, you can do:
let difference = arr1
.filter(x => !arr2.includes(x))
.concat(arr2.filter(x => !arr1.includes(x)));
This way, you will get an array containing all the elements of arr1 that are not in arr2 and vice-versa
As #Joshaven Potter pointed out on his answer, you can add this to Array.prototype so it can be used like this:
Array.prototype.diff = function(arr2) { return this.filter(x => !arr2.includes(x)); }
[1, 2, 3].diff([2, 3])
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.
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"));
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
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]);
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'];
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;
}
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.)
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)) ]
To get the symmetric difference you need to compare the arrays in both ways (or in all the ways in case of multiple arrays)
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}]
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}
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 })
);
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().
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" ].
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]
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.
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);
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]
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
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)))
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"]
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(', ')
);
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}
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};
}
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
}