Wie bekomme ich den Unterschied zwischen zwei Arrays in Javascript?

Gibt es eine Möglichkeit, den Unterschied zwischen zwei Arrays in JavaScript zurückzugeben?

Beispielsweise:

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

Jeder Rat sehr geschätzt.

Ich nehme an, Sie vergleichen ein normales Array. Wenn nicht, müssen Sie die for- Schleife in eine for .. in- Schleife ändern.

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

Es gibt einen besseren Weg mit ES7:

Überschneidung

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

Schnittdifferenz Venn Diagramm

Für [1,2,3] [2,3] ergibt sich [2,3] . Auf der anderen Seite wird für [1,2,3] [2,3,5] dasselbe zurückkehren.

Unterschied

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

Richtiger Unterschied Venn Diagramm

Für [1,2,3] [2,3] ergibt sich [1] . Auf der anderen Seite wird für [1,2,3] [2,3,5] dasselbe zurückkehren.

Für einen symmetrischen Unterschied können Sie Folgendes tun:

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

Symmetrischer Unterschied Venn-Diagramm

Auf diese Weise erhalten Sie ein Array mit allen Elementen von arr1, die nicht in arr2 und umgekehrt sind

Wie @Joshaven Potter auf seine Antwort hingewiesen hat, kannst du das zu Array.prototype hinzufügen, so dass es wie folgt verwendet werden kann:

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

Dies ist bei weitem der einfachste Weg, mit jQuery genau das Ergebnis zu erhalten, das Sie suchen:

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

diff enthält jetzt, was in old_array , das nicht in new_array

Die Difference-Methode in Underscore (oder deren Drop-In-Ersatz, Lo-Dash ) kann dies auch:

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

Wie bei jeder Underscore-function können Sie sie auch in einem eher objektorientierten Stil verwenden:

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

Einfaches JavaScript

Es gibt zwei mögliche Interpretationen für “Differenz”. Ich lasse dich wählen, welches du willst. Sag du hast:

 var a1 = ['a', 'b' ]; var a2 = [ 'b', 'c']; 
  1. Wenn Sie ['a'] möchten, verwenden Sie diese 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; } 
  2. Wenn Sie ['a', 'c'] möchten (alle Elemente in a1 oder a2 , aber nicht beide - die sogenannte symmetrische Differenz ), verwenden Sie diese 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 / Unterstrich

Wenn Sie lodash verwenden, können Sie _.difference(a1, a2) (Fall 1 oben) oder _.xor(a1, a2) (Fall 2) verwenden.

Wenn Sie Underscore.js verwenden, können Sie die function _.difference(a1, a2) für Fall 1 verwenden.

ES6 Set, für sehr große Arrays

Der obige Code funktioniert auf allen Browsern. Bei großen Arrays mit mehr als etwa 10.000 Elementen wird es jedoch ziemlich langsam, da es O (n²) -Komplexität aufweist. In vielen modernen Browsern können wir das ES6 Set Objekt nutzen, um die Dinge zu beschleunigen. Lodash verwendet Set automatisch, wenn es verfügbar ist. Wenn Sie nicht lodash verwenden, verwenden Sie die folgende Implementierung, inspiriert von Axel Rauschmayers Blogpost :

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

Anmerkungen

Das Verhalten für alle Beispiele kann überraschend oder nicht offensichtlich sein, wenn Sie sich für -0, +0, NaN oder Sparse-Arrays interessieren. (Für die meisten Anwendungen ist dies egal.)

Sie könnten in diesem Fall ein Set verwenden . Es ist für diese Art von Operation (Vereinigung, Schnittpunkt, Differenz) optimiert.

Stellen Sie sicher, dass es auf Ihren Fall zutrifft, sobald es keine Duplikate erlaubt.

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

Vereinigen Sie beide Arrays, eindeutige Werte erscheinen nur einmal, so dass indexOf () dasselbe ist wie lastIndexOf ().

Um ein Array von einem anderen zu subtrahieren, verwenden Sie einfach das folgende Snippet:

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

Es gibt ['1,' 2 ',' 6 '] zurück, die Elemente des ersten Arrays sind, die nicht in dem zweiten Array vorhanden sind.

Daher ist der folgende Code entsprechend Ihrer Problemprobe genau die Lösung:

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

Eine Lösung, die indexOf() , ist für kleine Arrays in indexOf() aber mit zunehmender Länge nähert sich die performance des Algorithmus O(n^2) . Hier ist eine Lösung, die für sehr große Arrays besser funktioniert, indem Objekte als assoziative Arrays zum Speichern der Array-Einträge als Schlüssel verwendet werden. Es eliminiert auch doppelte Einträge automatisch, funktioniert aber nur mit String-Werten (oder Werten, die sicher als Strings gespeichert werden können):

 function arrayDiff(a1, a2) { var o1={}, o2={}, diff=[], i, len, k; for (i=0, len=a1.length; i ['c', 'd'] arrayDiff(a2, a1); // => ['c', 'd'] 

Mit der Ankunft von ES6 mit Sets und Splat-Operator (zur Zeit der Arbeit nur in Firefox, überprüfen Sie die Kompatibilitätstabelle ), können Sie den folgenden Liner schreiben:

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

was zu [ "c", "d" ] .

functioneller Ansatz mit ES2015

Das Berechnen der difference zwischen zwei Arrays ist eine der Set Operationen. Der Begriff gibt bereits an, dass der native Set Typ verwendet werden sollte, um die Suchgeschwindigkeit zu erhöhen. Wie auch immer, es gibt drei Permutationen, wenn Sie den Unterschied zwischen zwei Mengen berechnen:

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

Hier ist eine funktionale Lösung, die diese Permutationen widerspiegelt.

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

Die obige Antwort von Joshaven Potter ist großartig. Aber es liefert Elemente in Array B, die nicht in Array C sind, aber nicht umgekehrt. Zum Beispiel, wenn var a=[1,2,3,4,5,6].diff( [3,4,5,7]); dann wird es ausgeben: ==> [1,2,6] , aber nicht [1,2,6,7] , was der tatsächliche Unterschied zwischen den beiden ist. Sie können den obigen Potter-Code weiterhin verwenden, aber den Vergleich auch einmal rückwärts wiederholen:

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

Dies sollte ausgeben: [ 1, 2, 6, 7 ]

Eine andere Möglichkeit, das Problem zu lösen

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

Sehr einfache Lösung mit der Filterfunktion von 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); 

Wie wäre es damit:

 Array.prototype.contains = function(needle){ for (var i=0; i 

Auf diese Weise können Sie array1.diff(array2) , um ihre Differenz zu erhalten (schreckliche Zeitkomplexität für den Algorithmus - O (array1.length x array2.length) glaube ich)

Mit http://phrogz.net/JS/ArraySetMath.js können Sie:

 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"] 
  • Reine JavaScript-Lösung (keine Bibliotheken)
  • Kompatibel mit älteren Browsern (verwendet keinen filter )
  • O (n ^ 2)
  • Optionaler fn callbackparameter, mit dem Sie angeben können, wie Array-Elemente verglichen werden
 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(', ') ); 

Das funktioniert: fusionieren Sie die beiden Arrays im Grunde, suchen Sie nach den Duplikaten und schieben Sie das, was nicht dupliziert ist, in ein neues Array, was der Unterschied ist.

 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 
 function diffArray(arr1, arr2) { var newArr = arr1.concat(arr2); return newArr.filter(function(i){ return newArr.indexOf(i) == newArr.lastIndexOf(i); }); } 

das funktioniert für mich

Ich denke nur … um einer Herausforderung willen 😉 würde das funktionieren … (für einfache Arrays von Strings, Zahlen usw.) keine verschachtelten 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 

Beachten Sie, dass die Sortierung wahrscheinlich nicht so ist, wie oben erwähnt. Rufen Sie jedoch, falls gewünscht, .sort () für das Array auf, um es zu sortieren.

Littlebit Fix für die beste Antwort

 function arr_diff(a1, a2) { var a=[], diff=[]; for(var i=0;i 

Dies berücksichtigt den aktuellen Elementtyp. b / c Wenn wir [a1 [i]] machen, wird ein Wert von seinem ursprünglichen Wert in eine Zeichenkette umgewandelt, so dass wir den tatsächlichen Wert verloren haben.

Dies wurde von der akzeptierten Antwort von Thinker inspiriert, aber Thinkers Antwort scheint anzunehmen, dass die Arrays Sets sind. Es fällt auseinander, wenn die Arrays [ "1", "2" ] und [ "1", "1", "2", "2" ]

Der Unterschied zwischen diesen Arrays ist [ "1", "2" ] . Die folgende Lösung ist O (n * n), also nicht ideal, aber wenn Sie große Arrays haben, hat es Speichervorteile gegenüber der Thinker-Lösung.

Wenn Sie mit Sets arbeiten, ist die Lösung von Thinker definitiv besser. Wenn Sie eine neuere Version von Javascript mit Zugriff auf Filter haben, sollten Sie diese ebenfalls verwenden. Dies ist nur für diejenigen, die nicht mit Sets arbeiten und eine ältere Version von JavaScript verwenden (aus welchem ​​Grund auch immer) …

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

Wenn die Arrays keine einfachen Typen haben, kann eine der obigen Antworten angepasst werden:

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

Diese Methode funktioniert bei Arrays komplexer Objekte.

Ich wollte eine ähnliche function, die ein altes Array und ein neues Array einschloss und mir ein Array von hinzugefügten Elementen und ein Array von entfernten Elementen gab, und ich wollte, dass es effizient ist (also keine .enthält!).

Sie können mit meiner vorgeschlagenen Lösung hier spielen: http://jsbin.com/osewu3/12 .

Kann jemand irgendwelche Probleme / Verbesserungen zu diesem Algorithmus sehen? Vielen Dank!

Code-Liste:

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

Ich suchte nach einer einfachen Antwort, die nicht die Verwendung verschiedener Bibliotheken beinhaltete, und ich habe meine eigene gefunden, von der ich glaube, dass sie hier nicht erwähnt wurde. Ich weiß nicht, wie effizient es ist oder irgendetwas, aber es funktioniert;

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

Für meinen Code brauche ich auch Duplikate, aber ich denke das ist nicht immer bevorzugt.

Ich denke, der größte Nachteil ist, dass es möglicherweise viele Optionen vergleicht, die bereits abgelehnt wurden.

Als Antwort auf die Person, die ein Array von einem anderen subtrahieren wollte …

Wenn nicht mehr als 1000 Elemente das versuchen …

Richten Sie eine neue Variable ein, um Array01 zu duplizieren und es Array03 zu nennen.

Verwenden Sie nun den Blasensortieralgorithmus, um die Elemente von Array01 mit Array02 zu vergleichen, und wenn Sie eine Übereinstimmung finden, machen Sie Folgendes mit Array03 …

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

NB: Wir modifizieren Array03 anstelle von Array01, um die verschachtelten Schleifen der Bubble-Sortierung nicht zu vermasseln!

Kopieren Sie schließlich den Inhalt von Array03 mit einer einfachen Zuweisung in Array01, und Sie sind fertig.

Sie können unterscore.js verwenden: http://underscorejs.org/#intersection

Sie haben Methoden für das Array benötigt:

 _.difference([1, 2, 3, 4, 5], [5, 2, 10]); => [1, 3, 4] _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]); => [1, 2]