web-dev-qa-db-fra.com

Comment faire la différence entre deux tableaux en Javascript?

Existe-t-il un moyen de renvoyer la différence entre deux tableaux en JavaScript?

Par exemple:

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

// need ["c", "d"]

Tout conseil grandement apprécié.

547
John Adawan

Je suppose que vous comparez un tableau normal. Sinon, vous devez changer la boucle pour en une boucle pour .. dans .

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

Si vous ne vous souciez pas de la compatibilité ascendante, une meilleure solution consiste à utiliser le filtre. Mais toujours, cette solution fonctionne.

166
Thinker
Array.prototype.diff = function(a) {
    return this.filter(function(i) {return a.indexOf(i) < 0;});
};

////////////////////  
// Examples  
////////////////////

[1,2,3,4,5,6].diff( [3,4,5] );  
// => [1, 2, 6]

["test1", "test2","test3","test4","test5","test6"].diff(["test1","test2","test3","test4"]);  
// => ["test5", "test6"]

Array.prototype.diff = function(a) {
    return this.filter(function(i) {return a.indexOf(i) < 0;});
};

////////////////////  
// Examples  
////////////////////

var dif1 = [1,2,3,4,5,6].diff( [3,4,5] );  
console.log(dif1); // => [1, 2, 6]


var dif2 = ["test1", "test2","test3","test4","test5","test6"].diff(["test1","test2","test3","test4"]);  
console.log(dif2); // => ["test5", "test6"]

Remarque indexOf et le filtre ne sont pas disponibles avant ie9.

818
Joshaven Potter

Il y a une meilleure façon d'utiliser ES7:

Intersection

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

 Intersection difference Venn Diagram

Pour [1,2,3] [2,3], le résultat sera [2,3]. D'autre part, pour [1,2,3] [2,3,5] retournera la même chose.

Différence

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

 Right difference Venn Diagram

Pour [1,2,3] [2,3], le résultat sera [1]. D'autre part, pour [1,2,3] [2,3,5] retournera la même chose.

Pour une différence symétrique, vous pouvez faire:

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

 Symmetric difference Venn Diagram

De cette façon, vous obtiendrez un tableau contenant tous les éléments de arr1 qui ne sont pas dans arr2 et inversement

Comme @Joshaven Potter l'a souligné dans sa réponse, vous pouvez ajouter ceci à Array.prototype pour pouvoir l'utiliser comme suit:

Array.prototype.diff = arr1.filter(x => arr2.includes(x));
[1, 2, 3].diff([2, 3])
645
Luis Sieira

C'est de loin le moyen le plus simple d'obtenir exactement le résultat que vous recherchez, en utilisant jQuery:

var diff = $(old_array).not(new_array).get();

diff contient maintenant ce qui était dans old_array qui n'est pas dans new_array

298
superphonic

La méthode différence dans Underscore (ou son remplacement immédiat, Lo-Dash ) peut aussi faire cela:

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

Comme avec n'importe quelle fonction Underscore, vous pouvez également l'utiliser dans un style plus orienté objet:

_([1, 2, 3, 4, 5]).difference([5, 2, 10]);
147
mahemoff

JavaScript simple

Il y a deux interprétations possibles pour "différence". Je vous laisse choisir celui que vous voulez. Disons que vous avez:

var a1 = ['a', 'b'     ];
var a2 = [     'b', 'c'];
  1. Si vous voulez obtenir ['a'], utilisez cette fonction:

    function difference(a1, a2) {
      var result = [];
      for (var i = 0; i < a1.length; i++) {
        if (a2.indexOf(a1[i]) === -1) {
          result.Push(a1[i]);
        }
      }
      return result;
    }
    
  2. Si vous voulez obtenir ['a', 'c'] (tous les éléments contenus dans soita1 ou a2, mais pas les deux - la soi-disant différence symétrique), utilisez cette fonction:

    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

Si vous utilisez lodash, vous pouvez utiliser _.difference(a1, a2) (cas 1 ci-dessus) ou _.xor(a1, a2) (cas 2).

Si vous utilisez Underscore.js, vous pouvez utiliser la fonction _.difference(a1, a2) pour le cas 1.

ES6 Set, pour les très grands tableaux

Le code ci-dessus fonctionne sur tous les navigateurs. Cependant, pour les tableaux de grande taille contenant plus de 10 000 éléments environ, il devient assez lent, car il présente une complexité de O (n²). Sur de nombreux navigateurs modernes, nous pouvons tirer parti de l'objet ES6 Set pour accélérer les choses. Lodash utilise automatiquement Set lorsqu'il est disponible. Si vous n'utilisez pas lodash, utilisez l'implémentation suivante, inspirée de Le blog de Axel Rauschmayer :

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

Remarques

Le comportement de tous les exemples peut être surprenant ou non évident si vous vous souciez de -0, +0, NaN ou de tableaux épars. (Pour la plupart des utilisations, cela n'a pas d'importance.)

63
Jo Liss

Vous pouvez utiliser un Set dans ce cas. Il est optimisé pour ce type d'opération (union, intersection, différence).

Assurez-vous que cela s'applique à votre cas, une fois qu'il ne permet pas de doublons.

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}
33
Samuel Carrijo
function diff(a1, a2) {
  return a1.concat(a2).filter(function(val, index, arr){
    return arr.indexOf(val) === arr.lastIndexOf(val);
  });
}

Fusionner les deux tableaux, les valeurs uniques n'apparaîtront qu'une seule fois, donc indexOf () sera identique à lastIndexOf ().

28
pdbrito

Pour obtenir la différence symétrique, vous devez comparer les tableaux de deux manières (ou de toutes les manières en cas de tableaux multiples)

 enter image description here


ES7 (ECMAScript 2016)

// diff between just two arrays:
function arrayDiff(a, b) {
    return [
        ...a.filter(x => !b.includes(x)),
        ...b.filter(x => !a.includes(x))
    ];
}

// diff between multiple arrays:
function arrayDiff(...arrays) {
    return [].concat(...arrays.map( (arr, i) => {
        const others = arrays.slice(0);
        others.splice(i, 1);
        const unique = [...new Set([].concat(...others))];
        return arr.filter(x => !unique.includes(x));
    }));
}

ES6 (ECMAScript 2015)

// diff between just two arrays:
function arrayDiff(a, b) {
    return [
        ...a.filter(x => b.indexOf(x) === -1),
        ...b.filter(x => a.indexOf(x) === -1)
    ];
}

// diff between multiple arrays:
function arrayDiff(...arrays) {
    return [].concat(...arrays.map( (arr, i) => {
        const others = arrays.slice(0);
        others.splice(i, 1);
        const unique = [...new Set([].concat(...others))];
        return arr.filter(x => unique.indexOf(x) === -1);
    }));
}

ES5 (ECMAScript 5.1)

// diff between just two arrays:
function arrayDiff(a, b) {
    var arrays = Array.prototype.slice.call(arguments);
    var diff = [];

    arrays.forEach(function(arr, i) {
        var other = i === 1 ? a : b;
        arr.forEach(function(x) {
            if (other.indexOf(x) === -1) {
                diff.Push(x);
            }
        });
    })

    return diff;
}

// diff between multiple arrays:
function arrayDiff() {
    var arrays = Array.prototype.slice.call(arguments);
    var diff = [];

    arrays.forEach(function(arr, i) {
        var others = arrays.slice(0);
        others.splice(i, 1);
        var otherValues = Array.prototype.concat.apply([], others);
        var unique = otherValues.filter(function (x, j) { 
            return otherValues.indexOf(x) === j; 
        });
        diff = diff.concat(arr.filter(x => unique.indexOf(x) === -1));
    });
    return diff;
}

Exemple:

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

Différence entre les tableaux d'objets

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

Exemple:

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}]
23
Luca Borrione

pour soustraire un tableau à un autre, utilisez simplement l'extrait de code ci-dessous:

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

Il retournera ['1,' 2 ',' 6 '] qui sont des éléments du premier tableau qui n'existent pas dans le second.

Par conséquent, selon votre exemple de problème, le code suivant est la solution exacte:

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

Une solution utilisant indexOf() conviendra pour les baies de petite taille, mais à mesure qu’elles grandissent, les performances de l’algorithme se rapprochent de O(n^2). Voici une solution qui fonctionnera mieux pour les très grands tableaux en utilisant des objets comme des tableaux associatifs pour stocker les entrées du tableau sous forme de clés. cela élimine également les entrées en double automatiquement, mais ne fonctionne qu'avec des valeurs de chaîne (ou des valeurs pouvant être stockées en toute sécurité sous forme de chaînes):

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']
12
maerics

Approche fonctionnelle avec ES2015

Le calcul de difference entre deux tableaux est l’une des opérations Set. Le terme indique déjà que le type Set natif doit être utilisé afin d’accroître la vitesse de recherche. Quoi qu'il en soit, il existe trois permutations lorsque vous calculez la différence entre deux ensembles:

[+left difference] [-intersection] [-right difference]
[-left difference] [-intersection] [+right difference]
[+left difference] [-intersection] [+right difference]

Voici une solution fonctionnelle qui reflète ces permutations.

difference gauche:

// small, reusable auxiliary functions

const apply = f => x => f(x);
const flip = f => y => x => f(x) (y);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));


// left difference

const differencel = xs => ys => {
  const zs = createSet(ys);
  return filter(x => zs.has(x)
     ? false
     : true
  ) (xs);
};


// mock data

const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,3,6,7,8,9];


// run the computation

console.log( differencel(xs) (ys) );

difference droit:

differencer est trivial. C'est juste differencel avec des arguments retournés. Vous pouvez écrire une fonction pour plus de commodité: const differencer = flip(differencel). C'est tout!

Symétrique difference:

Maintenant que nous avons les solutions gauche et droite, la mise en œuvre de la variable difference symétrique devient également triviale:

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

Je suppose que cet exemple est un bon point de départ pour obtenir une impression de ce que la programmation fonctionnelle signifie:

Programmation avec des blocs de construction qui peuvent être connectés ensemble de nombreuses façons différentes.

11
user6445533

Avec l’arrivée de l’ES6 avec les ensembles et l’opérateur Splat (à l’heure où il fonctionne uniquement dans Firefox, vérifiez tableau de compatibilité ), vous pouvez écrire le liner suivant:

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

ce qui entraînera [ "c", "d" ].

11
Salvador Dali

La réponse ci-dessus de Joshaven Potter est excellente. Mais il retourne des éléments dans le tableau B qui ne sont pas dans le tableau C, mais pas l'inverse. Par exemple, si var a=[1,2,3,4,5,6].diff( [3,4,5,7]);, le résultat sera: ==> [1,2,6], mais pas [1,2,6,7], qui correspond à la différence entre les deux. Vous pouvez toujours utiliser le code de Potter ci-dessus, mais simplement refaire la comparaison une fois en arrière aussi:

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

Cela devrait générer: [ 1, 2, 6, 7 ]

10
user1685068

Une autre façon de résoudre le problème 

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]
8
Iurii Golskyi
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]
7
riyas tk

Que dis-tu de ça:

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

Donc, de cette façon, vous pouvez faire array1.diff(array2) pour obtenir leur différence (Horrible complexité temporelle pour l'algorithme cependant - O (array1.length x array2.length), je crois)

6
Cat

Solution très simple avec la fonction de filtrage de 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);

6
Yash Thakkar

En utilisant http://phrogz.net/JS/ArraySetMath.js vous pouvez:

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"]
4
Phrogz
  • Solution JavaScript pure (pas de bibliothèques)
  • Compatible avec les anciens navigateurs (n'utilise pas filter)
  • O(n^2)
  • Paramètre de rappel fn facultatif qui vous permet de spécifier comment comparer les éléments du tableau

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(', ')
);

3
Trevor

Cela fonctionne: fondamentalement, fusionnez les deux tableaux, recherchez les doublons et transférez ce qui n'est pas dupliqué dans un nouveau tableau qui constitue la différence.

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

3
Giorgio Giuliani
function diffArray(arr1, arr2) {
  var newArr = arr1.concat(arr2);
  return newArr.filter(function(i){
    return newArr.indexOf(i) == newArr.lastIndexOf(i);
  });
}

ça marche pour moi

3
Stan D

Il suffit de penser ... pour relever un défi ;-) cela fonctionnerait-il ... (pour les tableaux de base de chaînes, de nombres, etc.)

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

Notez que le tri ne sera probablement pas comme indiqué ci-dessus ... mais si vous le souhaitez, appelez .sort () sur le tableau pour le trier.

2
scunliffe

petit correctif pour la meilleure réponse

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

cela tiendra compte du type d'élément actuel. b/c lorsque nous faisons un [a1 [i]], il convertit une valeur en chaîne à partir de sa valeur initiale, nous avons donc perdu la valeur réelle.

2
Vedanta-krit das

// es6 approche 

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
}
2
copremesis

encore une autre réponse, mais personne ne semble avoir mentionné jsperf où ils comparent plusieurs algorithmes et support technique: https://jsperf.com/array-difference-javascript semble utiliser le filtre pour obtenir les meilleurs résultats. Merci

2
cancerbero

Cela a été inspiré par la réponse acceptée par Thinker, mais celle-ci semble supposer que les tableaux sont des ensembles. Il tombe en morceaux si les tableaux sont [ "1", "2" ] et [ "1", "1", "2", "2" ]

La différence entre ces tableaux est [ "1", "2" ]. La solution suivante est O (n * n), donc pas idéale, mais si vous avez de grands tableaux, elle offre également des avantages en termes de mémoire par rapport à la solution de Thinker. 

Si vous avez affaire à des décors en premier lieu, la solution de Thinker est définitivement meilleure. Si vous avez une version plus récente de Javascript avec accès aux filtres, vous devez également les utiliser. Ceci est uniquement pour ceux qui ne traitent pas avec des ensembles et utilisent une version plus ancienne de JavaScript (pour une raison quelconque) ...

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

Si les tableaux ne sont pas de types simples, l'une des réponses ci-dessus peut être adaptée:

Array.prototype.diff = function(a) {
        return this.filter(function(i) {return a.map(function(e) { return JSON.stringify(e); }).indexOf(JSON.stringify(i)) < 0;});
    };

Cette méthode fonctionne sur des tableaux d'objets complexes.

2
Vadim
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]
2
huy-tran

Complexité symétrique et linéaire . Nécessite ES6. 

function arrDiff(arr1, arr2) {
    var arrays = [arr1, arr2].sort((a, b) => a.length - b.length);
    var smallSet = new Set(arrays[0]);

    return arrays[1].filter(x => !smallSet.has(x));
}
1
Dodgie

En réponse à la personne qui voulait soustraire un tableau d'un autre ...

Si pas plus de 1000 éléments essayent ceci ...

Configurez une nouvelle variable pour dupliquer Array01 et appelez-la Array03.

A présent, utilisez l’algorithme de tri à bulle pour comparer les éléments de Array01 avec Array02 et chaque fois que vous trouvez une correspondance.

 if (Array01[x]==Array02[y]) {Array03.splice(x,1);}

NB: Nous modifions Array03 au lieu de Array01 afin de ne pas gâcher les boucles imbriquées du type à bulles!

Enfin, copiez le contenu de Array03 dans Array01 avec une simple affectation et vous avez terminé.

1
MPS

Version CoffeeScript:

diff = (val for val in array1 when val not in array2)
1
m.e.conroy

Vous pouvez utiliser underscore.js: http://underscorejs.org/#intersection

Vous avez eu besoin de méthodes pour 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]
1
Sebastien

Je voulais une fonction similaire qui prenait un ancien tableau et un nouveau tableau et me donnait un tableau d'éléments ajoutés et un tableau d'éléments supprimés, et je voulais que ce soit efficace (donc non. Contient.!.

Vous pouvez jouer avec la solution proposée ici: http://jsbin.com/osewu3/12 .

Quelqu'un peut-il voir des problèmes/améliorations à cet algorithme? Merci!

Liste de code:

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}; 
}
1
Ian Grainger

Compare simplement toutes les valeurs et renvoie le tableau avec les valeurs qui ne se répètent pas.

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!"
1
MarekZeman91

Je cherchais une réponse simple qui n'impliquait pas l'utilisation de bibliothèques différentes et j'ai proposé la mienne que je ne pense pas mentionnée ici .. Je ne sais pas si c'est efficace ou quoi que ce soit d'autre travaux;

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

Pour mon code, il faut également supprimer les doublons, mais je suppose que ce n'est pas toujours préférable.

Je suppose que le principal inconvénient est qu'il est potentiellement possible de comparer de nombreuses options qui ont déjà été rejetées.

1
Samuel

Si hasOwnProperty n'est pas utilisé, nous avons des éléments incorrects. Par exemple: 

[1,2,3].diff([1,2]); //Return ["3", "remove", "diff"] This is the wrong version

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

Similaire à la solution de Ian Grainger (mais en 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' ] 
// }
1
Ardeshir Valipoor

Contribuer avec une solution jQuery que j'utilise actuellement:

if (!Array.prototype.diff) {
    Array.prototype.diff = function (a) {
        return $.grep(this, function (i) { return $.inArray(i, a) === -1; });
    }; 
}
1
Johan

The hard way (au cas où vous voudriez faire quelque chose de plus sophistiqué que .indexOf)

var difference = function (source, target) {
    return source.reduce(function (diff, current) { 
        if (target.indexOf(current) === -1) { 
            diff.Push(current); 
        }

        return diff; 
    }, []);
}

La solution de facilité

var difference = function (source, target) {
    return source.filter(function (current) {
        return target.indexOf(current) === -1;
    });
}
0
Santhos

voici la fonction que j'utilise pour obtenir la différence entre 2 tableaux. pas d'objet littéral dans les tableaux/tableaux multidimentionnels

function diff(arr1, arr2) {

    var x, 
        t;

    function uniq(a, b) {
        t = b;

        if( (b === 0 && x[b+1]!==a) || 
           (t > 0 && a !== x[b+1] && a !== x[b-1]) ) {
            return  a;
        }
    }


    x = arr1.concat(arr2).sort();

    return x.filter(uniq);
}

var a1 = ['a', 'b', 'e', 'c'],
    a2 = ['b', 'a', 'c', 'f' ];

diff(a1, a2);
0
jfab fab
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]);
}

C'est simple. Peut aussi être utilisé avec des objets en cochant une propriété d'objet ..__

if (a2[i].id === a1[j].id) found = true;

Si votre tableau contient des objets, cela devient un peu plus difficile si vous voulez comparer un attribut.

Heureusement, lodash facilite cela avec _contains et _.pluck:

var list1 = [{id: 1},{id: 2}];
var list1 = [{id: 1},{id: 2}, {id: 3}];

//es6
var results = list2.filter(item => {
  return !_.contains(_.pluck(list1, 'id'), item.id);
});

//es5
var results = list2.filter(function(item){
  return !_.contains(_.pluck(list1, 'id'), item.id);
});

//results contains [{id: 3}]
0
chovy

Solution rapide. Bien qu'il semble que d'autres aient déjà publié différentes variantes de la même méthode. Je ne suis pas sûr que ce soit le meilleur pour les baies de grande taille, mais cela fonctionne pour mes baies qui ne dépassent pas 10 ou 15.

Différence 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);
    }
  }
}
0
Ajoy

Cette question est ancienne mais reste le problème le plus populaire pour la soustraction de tableaux javascript , donc je voulais ajouter la solution que j'utilise. Cela convient pour le cas suivant:

var a1 = [1,2,2,3]
var a2 = [1,2]
//result = [2,3]

La méthode suivante produira le résultat souhaité:

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

Il est à noter que la fonction n'inclut pas les valeurs de la soustraction qui ne sont pas présentes dans la minuend:

var a1 = [1,2,3]
var a2 = [2,3,4]
//result = [1]
0
cazzer

si vous ne vous souciez pas des tableaux originaux et n'avez aucun problème pour les éditer, alors cet algorithme est plus rapide:

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

0
Rohanil
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);
0
fog
const difference = function (baseArray, arrayToCampare, callback = (a, b) => a!== b) {
  if (!(arrayToCampare instanceof Array)) {
    return baseArray;
  }
  return baseArray.filter(baseEl =>
    arrayToCampare.every(compareEl => callback(baseEl, compareEl)));
}
0
Yaremenko Andrii
function array_diff(a, b) {

    let array = [];
    for(let i = 0; i <a.length; i++) {
        let k = 0;
        for( let j = 0; j < b.length; j++) {
            if(a[i]!==b[j]) {
                k++;
            }
            if(k===b.length) {
                array = array.concat(a[i]);
            }
        }

        if(b.length ===0) {
            array = array.concat(a[i]);
        }
    }
    return array;
}
0
user608540
var arrayDifference = function(arr1, arr2){
  if(arr1 && arr1.length){
    if(arr2 && arr2.length > 0){
      for (var i=0, itemIndex; i<arr2.length; i++){
        itemIndex = arr1.indexOf(arr2[i]);
        if(itemIndex !== -1){
          arr1.splice(itemIndex, 1);
        }
      }
    }
    return arr1;
  }
  return [];
};

arrayDifference([1,2,3,4,5], [1,5,6]);
0
Aswin Ramesh

Vous pouvez utiliser un objet commun et compter la fréquence de chaque valeur du premier tableau. Pour le second tableau, décrémentez la valeur dans l'objet commun. Puis parcourez toutes les clés et ajoutez toutes les clés dont la valeur est supérieure à 1.

const difference = (a1, a2) => {
  var obj = {};
  a1.forEach(v => obj[v] = (obj[v] || 0) + 1);
  a2.forEach(v => obj[v] = (obj[v] || 0) - 1);
  return Object
      .keys(obj)
      .reduce((r,k) => {
        if(obj[k] > 0)
          r = r.concat(Array.from({length: obj[k]}).fill(k));
        return r;
      },[]);
};
const result = difference(['a', 'a', 'b', 'c', 'd'], ['a', 'b']);
console.log(result);

0
Hassan Imam

Voici comment j'obtiens deux tableaux de différence. Pur et propre.

Il retournera un objet contenant [add list] et [remove list].

  function getDiff(past, now) {
        let ret = { add: [], remove: [] };
        for (var i = 0; i < now.length; i++) {
          if (past.indexOf(now[i]) < 0)
            ret['add'].Push(now[i]);
        }
        for (var i = 0; i < past.length; i++) {
          if (now.indexOf(past[i]) < 0)
            ret['remove'].Push(past[i]);
        }
        return ret;
      }
0
rosethorn999

Voici ce que j'utilise:

var newArr = a1.filter(function(elem) {
            return a2.indexOf(elem) === -1;
        }).concat( a2.filter(function(elem) {
            return a1.indexOf(elem) === -1;
        }));
console.log(newArr);

ou celui-ci

var newArr = a1.concat(a2);
        function check(item) {
            if (a1.indexOf(item) === -1 || a2.indexOf(item) === -1) {
                return item;
            }
        }
        return newArr.filter(check);
0
Koushik Das

J'ai essayé toutes les solutions ci-dessus, mais aucune solution ne fonctionnait lorsque vous deviez effectuer une correspondance sans accepter les doublons.

Par exemple:

var a1 = [1, 2, 1, 4], a2 = [1, 2, 4];

Renverrait un tableau diff vide car 2 serait trouvé une fois dans le deuxième tableau, même si nous avons besoin qu'il corresponde deux fois.

J'ai donc réussi à arranger quelque chose:

Array.prototype.diff = function(a) {
    return this.filter(function(item) {
        match = a.indexOf(item);
        if (match)
            a.splice(match, 1);
        return match < 0;
    });
};
0
casraf

La réponse sélectionnée n’est que la moitié correcte. Vous devez comparer les tableaux des deux manières pour obtenir une réponse complète. 

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' ]
0
Flavio

Cela me semble plus facile de traiter cela comme des fonctions partielles. Assez surpris de ne pas voir de solution de programmation fonctionnelle, voici le mien dans ES6:

const arrayDiff = (a, b) => {
  return diff(b)(a);
}

const contains = (needle) => (array) => {
  for (let i=0; i < array.length; i++) {
    if (array[i] == needle) return true;
  }

  return false;
}

const diff = (compare) => {
    return (array) => array.filter((elem) => !contains(elem)(compare))
}
0
Decebal

Les réponses que je lis ici comportent beaucoup de problèmes qui leur confèrent une valeur limitée dans les applications de programmation pratiques.

D'abord et avant tout, vous allez vouloir avoir un moyen de contrôler ce que cela signifie pour deux éléments du tableau d'être "égaux". La comparaison === ne va pas la couper si vous essayez de savoir s'il faut mettre à jour un tableau d'objets basé sur un ID ou quelque chose du genre, ce qui est probablement l'un des scénarios les plus probables dans lesquels vous voudrez une fonction diff. Cela vous limite également à des tableaux de choses qui peuvent être comparés à l'opérateur ===, à savoir des chaînes, des entiers, etc., et c'est à peu près inacceptable pour les adultes.

Deuxièmement, il existe trois résultats d'état d'une opération diff:

  1. éléments qui sont dans le premier tableau mais pas dans le second
  2. éléments communs aux deux tableaux
  3. éléments qui sont dans le second tableau mais pas dans le premier

Je pense que cela signifie que vous n’avez pas besoin de moins de 2 boucles, mais je suis ouvert à de mauvaises astuces si quelqu'un sait comment le réduire à un.

Voici quelque chose que j'ai concocté, et je tiens à souligner que JE NE VEUX ABSOLUMENT PAS que cela ne fonctionne pas dans les anciennes versions de navigateurs Microshaft. Si vous travaillez dans un environnement de codage inférieur, tel que IE, il vous appartient de le modifier pour respecter les limitations insatisfaisantes que vous vous êtes imposées.

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;

};
0
Mason Houtz

Les données:

var new_storage = JSON.parse('[{"id_order":"0003"},{"id_order":"0004"},{"id_order":"0006"}]');

var old_storage = JSON.parse('[{"id_order":"0001"},{"id_order":"0002"},{"id_order":"0003"},{"id_order":"0004"},{"id_order":"0005"}]');

en utilisant un filtre:

var diff = new_storage
.filter(x => {if(!(old_storage.filter(y => y.id_order==x.id_order)).length){return x}})
    .concat(old_storage
    .filter(x => {if(!(new_storage.filter(y => y.id_order==x.id_order)).length){return x}})
                       ) 

console.log(JSON.stringify(diff))

différence de résultat dans deux tableaux

[{"id_order":"0006"},{"id_order":"0001"},{"id_order":"0002"},{"id_order":"0005"}]
0
uscamayta

** Ceci retourne un tableau de valeurs uniques, ou un tableau de doublons, ou un tableau de non-doublons (différence) pour tout tableau sur la base de l'argument 'type'. ** 

let json1 = ['one', 'two']
let json2 = ['one', 'two', 'three', 'four']

function uniq_n_shit (arr1, arr2, type) {

  let concat = arr1.concat(arr2)
  let set = [...new Set(concat)]

  if (!type || type === 'uniq' || type === 'unique') {

    return set

  } else if (type === 'duplicate') {

    concat = arr1.concat(arr2)
    return concat.filter(function (obj, index, self) {
      return index !== self.indexOf(obj)
    })

  } else if (type === 'not_duplicate') {

    let duplicates = concat.filter(function (obj, index, self) {
      return index !== self.indexOf(obj)
    })

    for (let r = 0; r < duplicates.length; r++) {
      let i = set.indexOf(duplicates[r]);
      if(i !== -1) {
        set.splice(i, 1);
      }
    }

    return set

  }
}

console.log(uniq_n_shit(json1, json2, null)) // => [ 'one', 'two', 'three', 'four' ]
console.log(uniq_n_shit(json1, json2, 'uniq')) // => [ 'one', 'two', 'three', 'four' ]
console.log(uniq_n_shit(json1, json2, 'duplicate')) // => [ 'one', 'two' ]
console.log(uniq_n_shit(json1, json2, 'not_duplicate')) // => [ 'three', 'four' ]
0
Flavio

il suffit de couper la chaîne pour s'assurer que .... les espaces n'affecteront pas le diff

function arr_diff(a1, a2) {
    var a=[], diff=[];
    for(var i=0;i<a1.length;i++)
        a[a1[i]]=true;
    for(var i=0;i<a2.length;i++)
        if(a[a2[i].trim()]) delete a[a2[i].trim()];
    else a[a2[i].trim()]=true;
    for(var k in a)
        diff.Push(k);
    return diff;
}
0
Sivanagaiah

Samuel: "Pour mon code, j'ai besoin de supprimer les doublons également, mais je suppose que ce n'est pas toujours préférable."

Lorsque l'on compare DEUX listes, tableaux, etc., et que les éléments sont inférieurs à 1 000, la norme dans le monde du 3GL consiste à utiliser le type de bulle qui évite les dupes. 

Le code ressemblerait à quelque chose comme ça ... (non testé mais ça devrait marcher)

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;

Pour tester la sortie ...

for(y=0; y<Array01.length; y++) {document.write(Array01[y])}
0
MPS