John Adawan
John Adawan

Reputation: 14157

How to get the difference between two arrays in JavaScript?

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

Upvotes: 1396

Views: 1243968

Answers (30)

Luis Sieira
Luis Sieira

Reputation: 31612

Array.prototype.filter() and Array.prototype.includes() come in handy here.


Intersection

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

Intersection Venn Diagram

Yields values which are present in both A and B.

let A, B, intersection;

A = [1, 2, 3];
B =    [2, 3];
intersection = A.filter(x => B.includes(x));
console.log(intersection);

A = [1, 2, 3];
B =    [2, 3, 5];
intersection = A.filter(x => B.includes(x));
console.log(intersection);

// both operations return [2, 3]


Difference

(Values in just A.)

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

Right difference Venn Diagram

Yields values that are present in just A.

let A, B, intersection;

A = [1, 2, 3];
B =    [2, 3];
intersection = A.filter(x => !B.includes(x));
console.log(intersection);

A = [1, 2, 3];
B =    [2, 3, 5];
intersection = A.filter(x => !B.includes(x));
console.log(intersection);

// both operations return [1]


Symmetric Difference

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

Symmetric difference Venn Diagram

Yields values that are only in A or B, 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 A that are not in B and vice-versa).

let A, B, intersection;

A = [1, 2, 3];
B =    [2, 3];
intersection = A.filter(x => !B.includes(x))
    .concat(B.filter(x => !A.includes(x)));
console.log(intersection);

// returns [1]

A = [1, 2, 3];
B =    [2, 3, 5];
intersection = A.filter(x => !B.includes(x))
    .concat(B.filter(x => !A.includes(x)));
console.log(intersection);

// returns [1, 5]


See the answer by @Joshaven Potter, for an example of how you can use these functions directly on arrays.

Upvotes: 3006

Manu Rastogi
Manu Rastogi

Reputation: 188

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

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

console.log(diffArr);

Output:

[ 'c', 'd' ]

Upvotes: 6

時雨初
時雨初

Reputation: 473

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)

Upvotes: 0

Eliya Gervas
Eliya Gervas

Reputation: 87

const dbData = [{name:'ally'}, 
{name:'James'}]
const localData = [{name:'James'}] 

const diff = dbData.filter(a =>!localData.some(b => { return a.name === b.name}))

Upvotes: 3

Aliunco
Aliunco

Reputation: 399

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}

Upvotes: 5

Md Khairul Islam
Md Khairul Islam

Reputation: 461

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 ]

Upvotes: 0

Muazzez
Muazzez

Reputation: 13

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;
}

Upvotes: 0

nkitku
nkitku

Reputation: 5738

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 })
  );

Upvotes: 44

hamedkke
hamedkke

Reputation: 47

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

Upvotes: 3

Vikas Gupta
Vikas Gupta

Reputation: 1343

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

Upvotes: 8

cbush06
cbush06

Reputation: 66

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

A couple of options:

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

const hash = {};

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

var i1 = 0;
for(var i2 = 0; i2 < arrTwo.length; i2++) {
  while(arrOne[i1] < arrTwo[i2+1]) {
    if(arrOne[i1] != arrTwo[i2]) {
      console.log(arrOne[i1]);
    }
    i1++;
  }
}

Upvotes: 0

Thinker
Thinker

Reputation: 14464

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"));

Upvotes: 387

crg
crg

Reputation: 4577

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)

Upvotes: 3

Joshaven Potter
Joshaven Potter

Reputation: 10356

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.

Upvotes: 960

KJ Sudarshan
KJ Sudarshan

Reputation: 3252

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

Upvotes: 5

Cenkay AYDIN
Cenkay AYDIN

Reputation: 74

    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)));
    }

Upvotes: 1

Pram
Pram

Reputation: 2501

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

Upvotes: 0

Salvador Dali
Salvador Dali

Reputation: 222841

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

Upvotes: 34

Vishal
Vishal

Reputation: 826

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.

Upvotes: 0

Yurii Holskyi
Yurii Holskyi

Reputation: 928

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]

Upvotes: 16

Joe Seifi
Joe Seifi

Reputation: 1725

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);
}

Upvotes: 0

Luk&#225;š Ř&#225;dek
Luk&#225;š Ř&#225;dek

Reputation: 1441

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

Upvotes: 1

Ashish Yadav
Ashish Yadav

Reputation: 3196

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

Upvotes: 3

Ayyaz Zafar
Ayyaz Zafar

Reputation: 2163

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

Upvotes: 1

ifelse.codes
ifelse.codes

Reputation: 2389

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

Upvotes: 78

Mr. Polywhirl
Mr. Polywhirl

Reputation: 48693

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; }

Upvotes: 0

Rohanil
Rohanil

Reputation: 1887

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

Upvotes: 0

Ardeshir Valipoor
Ardeshir Valipoor

Reputation: 106

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' ] 
// }

Upvotes: 2

cancerbero
cancerbero

Reputation: 7045

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

Upvotes: 3

Farid Jafarlee
Farid Jafarlee

Reputation: 33

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;

Upvotes: 2

Related Questions