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"]
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 ];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.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; });
};
}
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
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]
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;
});
};
O(a1.length x log(a2.length))- is this performance possible in JavaScript?