Как получить разницу между двумя массивами в Javascript?

Есть ли способ вернуть разницу между двумя массивами в JavaScript?

Например:

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

Любые советы очень оценили.

30 Solutions collect form web for “Как получить разницу между двумя массивами в Javascript?”

Я предполагаю, что вы сравниваете обычный массив. Если нет, вам нужно изменить цикл for на цикл for .. in .

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

Существует лучший способ использования ES7:

пересечение

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

Пересечение разницы Диаграмма Венна

Для [1,2,3] [2,3] оно даст [2,3] . С другой стороны, для [1,2,3] [2,3,5] будет возвращено то же самое.

разница

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

Правильная разница Диаграмма Венна

Для [1,2,3] [2,3] оно даст [1] . С другой стороны, для [1,2,3] [2,3,5] будет возвращено то же самое.

Для симметричной разницы вы можете:

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

Симметричная разностная диаграмма Венна

Таким образом, вы получите массив, содержащий все элементы arr1, которые не находятся в arr2, и наоборот

Как пояснил @Joshaven Potter о своем ответе, вы можете добавить это в Array.prototype, чтобы его можно было использовать следующим образом:

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

Это самый простой способ получить именно тот результат, который вы ищете, используя jQuery:

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

diff теперь содержит то, что было в old_array который не находится в new_array

Разностный метод в Underscore (или его замещающая замена, Lo-Dash ) также может сделать это:

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

Как и любая функция Underscore, вы также можете использовать ее в более объектно-ориентированном стиле:

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

Обычный JavaScript

Есть две возможности для «разницы». Я позволю тебе выбрать, какой ты хочешь. Скажем, у вас есть:

 var a1 = ['a', 'b' ]; var a2 = [ 'b', 'c']; 
  1. Если вы хотите получить ['a'] , используйте эту функцию:

     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. Если вы хотите получить ['a', 'c'] (все элементы, содержащиеся в a1 или a2 , но не оба - так называемая симметричная разность ), используйте эту функцию:

     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

Если вы используете lodash, вы можете использовать _.difference(a1, a2) (пример 1 выше) или _.xor(a1, a2) (случай 2).

Если вы используете Underscore.js, вы можете использовать _.difference(a1, a2) для случая 1.

ES6 Набор для очень больших массивов

Этот код работает во всех браузерах. Тем не менее, для больших массивов более чем около 10000 элементов он становится довольно медленным, поскольку он имеет сложность O (n²). Во многих современных браузерах мы можем использовать объект ES6 Set для ускорения работы. Lodash автоматически использует Set когда он доступен. Если вы не используете lodash, используйте следующую реализацию, основанную на блоге 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)); } 

Заметки

Поведение для всех примеров может быть неожиданным или неочевидным, если вы заботитесь о -0, +0, NaN или разреженных массивах. (Для большинства применений это не имеет значения.)

В этом случае вы можете использовать Set . Он оптимизирован для такого рода операций (объединение, пересечение, разность).

Удостоверьтесь, что это относится к вашему делу, если оно не допускает дубликатов.

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

Объединить оба массива, уникальные значения появятся только один раз, поэтому indexOf () будет таким же, как lastIndexOf ().

чтобы вычесть один массив из другого, просто используйте fragment ниже:

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

Он вернет ['1,' 2 ',' 6 '], которые являются элементами первого массива, которые не существуют во втором.

Поэтому, согласно вашему образцу проблемы, следующий код является точным решением:

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

Решение с использованием indexOf() будет нормально для небольших массивов, но по мере их роста производительность алгоритма приближается к O(n^2) . Вот решение, которое будет работать лучше для очень больших массивов, используя объекты в качестве ассоциативных массивов для хранения записей массива в виде ключей; он также автоматически удаляет повторяющиеся записи, но работает только со строковыми значениями (или значениями, которые можно безопасно хранить в виде строк):

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

С появлением ES6 с наборами и оператором splat (во время работы только в Firefox, проверьте таблицу совместимости ), вы можете написать следующий один лайнер:

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

что приведет к [ "c", "d" ] .

Функциональный подход с ES2015

Вычисление difference между двумя массивами является одной из операций Set . Термин уже указывает, что должен использоваться собственный тип Set , чтобы увеличить скорость поиска. Во всяком случае, есть три перестановки, когда вы вычисляете разницу между двумя наборами:

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

Вот функциональное решение, которое отражает эти перестановки.

Левая 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) ); 

Вышеприведенный ответ Джошавеном Поттером велик. Но он возвращает элементы в массиве B, которые не находятся в массиве C, но не наоборот. Например, если var a=[1,2,3,4,5,6].diff( [3,4,5,7]); то он будет выводить: ==> [1,2,6] , но не [1,2,6,7] , что является фактической разницей между ними. Вы все равно можете использовать код Поттера выше, но просто повторите сравнение сразу же назад:

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

Это должно выводить: [ 1, 2, 6, 7 ]

Другой способ решения проблемы

 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] 

Очень простое решение с функцией фильтрации JavaScript:

 var a1 = ['a', 'b']; var a2 = ['a', 'b', 'c', 'd']; function diffArray(arr1, arr2) { var newArr = []; var myArr = arr1.concat(arr2); newArr = myArr.filter(function(item){ return arr2.indexOf(item) < 0 || arr1.indexOf(item) < 0; }); alert(newArr); } diffArray(a1, a2); 

Как насчет этого:

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

Таким образом, вы можете сделать array1.diff(array2) чтобы получить их различие (Ужасная временная сложность для алгоритма - O (array1.length x array2.length), я считаю)

Используя http://phrogz.net/JS/ArraySetMath.js, вы можете:

 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"] 
  • Чистое решение для JavaScript (без библиотек)
  • Совместим со старыми браузерами (не использует filter )
  • O (N ^ 2)
  • Необязательный параметр fn callback, который позволяет указать, как сравнивать элементы массива
 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(', ') ); 

Это работает: в основном слияние двух массивов, поиск дубликатов и толкать то, что не дублируется в новый массив, что является разницей.

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

это работает для меня

Просто думая … ради задачи 😉 будет ли это работать … (для базовых массивов строк, чисел и т. Д.) Нет вложенных массивов

 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 

Обратите внимание, что сортировка, скорее всего, не будет такой, как указано выше ... но при желании вызовите .sort () в массиве, чтобы отсортировать ее.

маленькое исправление для лучшего ответа

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

это будет учитывать текущий тип элемента. b / c, когда мы делаем [a1 [i]], он преобразует значение в строку из своего исходного значения, поэтому мы потеряли фактическое значение.

Это было вдохновлено принятым ответом Мыслителя, но ответ Мыслителя, похоже, предполагает, что массивы являются множествами. Он разваливается, если массивы [ "1", "2" ] и [ "1", "1", "2", "2" ]

Разница между этими массивами равна [ "1", "2" ] . Следующее решение – O (n * n), поэтому не идеально, но если у вас большие массивы, у него есть преимущества памяти по сравнению с решением Thinker.

Если вы имеете дело с наборами в первую очередь, решение Thinker определенно лучше. Если у вас есть более новая версия Javascript с доступом к фильтрам, вы также должны использовать их. Это только для тех, кто не имеет дело с наборами и использует старую версию JavaScript (по какой-либо причине) …

 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] 

Если массивы не имеют простых типов, то один из вышеперечисленных ответов может быть адаптирован:

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

Этот метод работает с массивами сложных объектов.

Мне нужна была аналогичная функция, которая использовалась в старом массиве и новом массиве и дала мне массив добавленных элементов и массив удаленных элементов, и я хотел, чтобы он был эффективным (так что нет .contains!).

Вы можете играть с моим предлагаемым решением здесь: http://jsbin.com/osewu3/12 .

Может ли кто-нибудь увидеть какие-либо проблемы / улучшения в этом алгоритме? Благодаря!

Список кодов:

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

Я искал простой ответ, который не включал использование разных библиотек, и я придумал свои собственные, о которых, я думаю, не упоминалось. Я не знаю, насколько он эффективен или что-то еще, но он работает;

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

Для моего кода мне тоже нужны дубликаты, но я думаю, что это не всегда предпочтительнее.

Я предполагаю, что основной недостаток - это потенциальное сравнение многих вариантов, которые уже были отклонены.

В ответ на человека, который хотел вычесть один массив из другого …

Если не более 1000 элементов, попробуйте это …

Установите новую переменную, чтобы дублировать Array01 и называть ее Array03.

Теперь используйте алгоритм сортировки пузырьков для сравнения элементов Array01 с Array02, и всякий раз, когда вы найдете совпадение, выполните следующие действия с Array03 …

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

NB: Мы модифицируем Array03 вместо Array01, чтобы не испортить вложенные петли пузырьковой сортировки!

Наконец, скопируйте содержимое Array03 в Array01 с простым назначением, и все готово.

Вы можете использовать underscore.js: http://underscorejs.org/#intersection

Вам нужны методы для массива:

 _.difference([1, 2, 3, 4, 5], [5, 2, 10]); => [1, 3, 4] _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]); => [1, 2] 
  • Реклама внезапно появляется поверх почти каждой страницы
  • Какова цель ключевого слова var и когда я должен использовать его (или опустить)?
  • Как читать локальный текстовый файл?
  • Безопасно ли публиковать Firebase apiKey?
  • Совместить целую строку
  • XMLHttpRequest не может загрузить XXX Нет заголовка «Access-Control-Allow-Origin»
  • jQuery AJAX submit form
  • Как использовать переменную для ключа в литерале объекта JavaScript?
  • Браузер командной строки с поддержкой js
  • Обнаружение закрытия браузера или вкладки
  • Rip веб-сайт через HTTP для загрузки изображений, HTML и CSS
  • Почему моя система ждет Google Analytics?
  • Давайте будем гением компьютера.