Есть ли способ вернуть разницу между двумя массивами в JavaScript?
Например:
var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];
// need ["c", "d"]
javascript
arrays
array-difference
Джон Адаван
источник
источник
O(a1.length x log(a2.length))
- возможна ли эта производительность в JavaScript?Ответы:
Я предполагаю, что вы сравниваете нормальный массив. Если нет, вам нужно изменить цикл for на цикл for .. in .
Лучшее решение, если вам не нужна обратная совместимость, - это использование фильтра. Но все же это решение работает.
источник
var a1 = ['a', 'b'];
иvar a2 = ['a', 'b', 'c', 'd', 'b'];
, он будет возвращать неверный ответ , то есть['c', 'd', 'b']
вместо['c', 'd']
.function diff2(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; }
Есть лучший способ использования ES7:
пересечение
Ибо
[1,2,3] [2,3]
это даст[2,3]
. С другой стороны, for[1,2,3] [2,3,5]
вернет то же самое.разница
Ибо
[1,2,3] [2,3]
это даст[1]
. С другой стороны, for[1,2,3] [2,3,5]
вернет то же самое.Для симметричной разницы вы можете сделать:
Таким образом, вы получите массив, содержащий все элементы arr1, которых нет в arr2, и наоборот
Как отметил @Joshaven Potter в своем ответе, вы можете добавить это в Array.prototype, чтобы его можно было использовать следующим образом:
источник
< 0
вместо== -1
Array
разницы является так называемымset operation
, потому что поиск свойства - это собственная работаSet
s, которая на несколько порядков быстрее, чемindexOf
/includes
. Проще говоря, ваше решение очень неэффективно и довольно медленно.Set
, значения должны быть уникальными, нет?[1,2,3] [2,3,5]
учитывая, что числа уникальны, но если бы вы сказали[1,1,2,3] [1,2,3,5]
и ожидали,[1]
что не сможете использоватьSet
. Ваше решение тоже не сработает: - / Я закончил создавать эту функцию, потому что не мог найти удовлетворительный способ сделать это более кратко. Если у вас есть идеи, как это сделать, я хотел бы знать!Array.includes()
ли функция ES7 вместо ES6? (1) (2) - и для продолжения ES6 вы можете использовать,Array.some()
напримерlet intersection = aArray.filter(a => bArray.some(b => a === b))
, нет?Показать фрагмент кода
Обратите внимание, что indexOf и фильтр недоступны в ie до ie9.
источник
[1,2,3].diff([3,4,5])
она вернется[1,2]
вместо того,[1,2,4,5]
чтобы не решить проблему в исходном вопросе, о чем следует знать.На сегодняшний день это самый простой способ получить именно тот результат, который вы ищете, используя jQuery:
diff
теперь содержит то, что было вold_array
том, что не вnew_array
источник
{a: 1} != {a: 1}
) ( доказательство ).not
массив, jQuery использует его встроенную утилиту,.grep()
специально предназначенную для фильтрации массивов. Я не вижу этого изменения.Разностный метод в Underscore (или его замена, Lo-Dash ) также может сделать это:
Как и с любой функцией Underscore, вы также можете использовать ее в более объектно-ориентированном стиле:
источник
Простой JavaScript
Есть два возможных объяснения «разницы». Я позволю вам выбрать, какой вы хотите. Скажем, у вас есть:
Если вы хотите получить
['a']
, используйте эту функцию:Если вы хотите получить
['a', 'c']
(все элементы, содержащиеся в одномa1
илиa2
, но не в обоих - так называемое симметричное различие ), используйте эту функцию:Лодаш / Подчеркивание
Если вы используете lodash, вы можете использовать
_.difference(a1, a2)
(случай 1 выше) или_.xor(a1, a2)
(случай 2).Если вы используете Underscore.js, вы можете использовать
_.difference(a1, a2)
функцию для случая 1.ES6 Set, для очень больших массивов
Код выше работает во всех браузерах. Однако для больших массивов, состоящих из более чем 10 000 элементов, он становится довольно медленным, поскольку имеет сложность O (n²). Во многих современных браузерах мы можем использовать
Set
объект ES6 для ускорения работы. Lodash автоматически использует,Set
когда он доступен. Если вы не используете lodash, используйте следующую реализацию, вдохновленную сообщением в блоге Акселя Раушмайера :Ноты
Поведение для всех примеров может быть удивительным или неочевидным, если вы заботитесь о -0, +0, NaN или разреженных массивах. (Для большинства случаев это не имеет значения.)
источник
Чтобы получить симметричную разницу, вам нужно сравнивать массивы обоими способами (или во всех случаях в случае нескольких массивов).
ES7 (ECMAScript 2016)
ES6 (ECMAScript 2015)
ES5 (ECMAScript 5.1)
Пример:
Разница между массивами объектов
Пример:
источник
Более чистый подход в ES6 является следующим решением.
разница
пересечение
Дизъюнктивный союз (симметричное различие)
источник
a1 = ['a', 'b', 'e']
: е не будут извлечены.Вы можете использовать набор в этом случае. Он оптимизирован для такого рода операций (объединение, пересечение, разность).
Убедитесь, что это применимо к вашему делу, как только оно не допускает дублирования.
источник
Set
функцию, не имея необходимости получать все остальное ...Объедините оба массива, уникальные значения появятся только один раз, поэтому indexOf () будет таким же, как lastIndexOf ().
источник
чтобы вычесть один массив из другого, просто используйте фрагмент ниже:
Он вернет ['1,' 2 ',' 6 '], которые являются элементами первого массива, которые не существуют во втором.
Следовательно, в соответствии с примером вашей проблемы, следующий код является точным решением:
источник
С появлением ES6 с множествами и оператором сплат (на момент работы только в Firefox, проверьте таблицу совместимости ), вы можете написать следующую строку:
что приведет к
[ "c", "d" ]
.источник
b.filter(x => !a.indexOf(x)))
O(n + m)
ваше решение,O(n * m)
где n и m - длины массивов. Возьмите длинные списки, и мое решение будет запущено в считанные секунды, а ваше - часами.a.filter(x => !b1.has(x))
проще И обратите внимание, спецификация требует, чтобы сложность была в среднемn * f(m) + m
сf(m)
сублинейной. Это лучше чемn * m
, но не обязательноn + m
.var difference = [...new Set([...a].filter(x => !b1.has(x)))];
Почему вы создаете дубликат массива 'a'? Почему вы превращаете результат фильтра в набор, а затем обратно в массив? Разве это не эквивалентноvar difference = a.filter(x => !b1.has(x));
Функциональный подход с ES2015
Вычисление
difference
двух массивов является одной изSet
операций. Термин уже указывает, чтоSet
для увеличения скорости поиска следует использовать собственный тип. В любом случае, при вычислении разницы между двумя наборами есть три перестановки:Вот функциональное решение, которое отражает эти перестановки.
Слева
difference
:Право
difference
:differencer
тривиально Это простоdifferencel
с перевернутыми аргументами. Вы можете написать функцию для удобства:const differencer = flip(differencel)
. Это все!Симметричный
difference
:Теперь, когда у нас есть левый и правый, реализация симметрии также
difference
становится тривиальной:Я полагаю, что этот пример является хорошей отправной точкой, чтобы получить представление о том, что означает функциональное программирование:
Программирование со строительными блоками, которые могут быть соединены вместе различными способами.
источник
Использование решения
indexOf()
будет хорошо для небольших массивов, но по мере увеличения их длины производительность алгоритма приближаетсяO(n^2)
. Вот решение, которое будет работать лучше для очень больших массивов, используя объекты в качестве ассоциативных массивов для хранения записей массива в качестве ключей; он также автоматически удаляет повторяющиеся записи, но работает только со строковыми значениями (или со значениями, которые можно безопасно хранить в виде строк):источник
Приведенный выше ответ Джошавена Поттера великолепен. Но он возвращает элементы в массиве B, которых нет в массиве C, но не наоборот. Например, если
var a=[1,2,3,4,5,6].diff( [3,4,5,7]);
тогда он выдаст: ==>[1,2,6]
, но нет[1,2,6,7]
, что является фактической разницей между ними. Вы все еще можете использовать приведенный выше код Поттера, но просто повторить сравнение и в обратном направлении:Это должно вывести:
[ 1, 2, 6, 7 ]
источник
Еще один способ решить проблему
Также вы можете использовать синтаксис функции стрелки:
источник
источник
difference
как функция в будущей версии, и тогда эта функция будет иметь другую сигнатуру функции, чем ваша, это нарушит ваш код или сторонние библиотеки, использующие эту функцию.Очень простое решение с функцией фильтра JavaScript:
источник
Как насчет этого:
Таким образом, вы можете сделать так,
array1.diff(array2)
чтобы получить их разницу (хотя ужасная сложность времени для алгоритма - O (array1.length x array2.length) я считаю)источник
Используя http://phrogz.net/JS/ArraySetMath.js, вы можете:
источник
это работает для меня
источник
filter
)fn
параметр обратного вызова, который позволяет указать, как сравнивать элементы массива.источник
length
значений. Это уже обычная собственность. jsperf.com/array-length-cachingЭто работает: в основном объедините два массива, найдите дубликаты и поместите то, что не дублируется, в новый массив, который является разницей.
источник
// es6 подход
источник
Симметричная и линейная сложность . Требуется ES6.
источник
еще один ответ, но, кажется, никто не упомянул jsperf, где они сравнивают несколько алгоритмов и техническую поддержку: https://jsperf.com/array-difference-javascript, кажется, использование фильтра дает лучшие результаты. Спасибо
источник
Просто думать ... ради вызова ;-) будет ли это работать ... (для базовых массивов строк, чисел и т. Д.) Нет вложенных массивов
Обратите внимание, что сортировка, вероятно, будет не такой, как указано выше ... но при желании вызовите .sort () для массива, чтобы отсортировать ее.
источник
Я хотел подобную функцию, которая использовала бы старый массив и новый массив и давал мне массив добавленных элементов и массив удаленных элементов, и я хотел, чтобы он был эффективным (поэтому нет .contains!).
Вы можете поиграть с моим предложенным решением здесь: http://jsbin.com/osewu3/12 .
Кто-нибудь может увидеть какие-либо проблемы / улучшения этого алгоритма? Спасибо!
Список кодов:
источник
Я искал простой ответ, который не предполагал использование разных библиотек, и я нашел свой собственный, который, я думаю, не был упомянут здесь. Я не знаю, насколько это эффективно или что-то еще, но это работает;
Для моего кода мне также нужно удалить дубликаты, но я думаю, что это не всегда предпочтительно.
Я предполагаю, что основным недостатком является то, что он потенциально сравнивает многие варианты, которые уже были отклонены.
источник
маленький бит исправить для лучшего ответа
это будет учитывать текущий тип элемента. b / c когда мы создаем [a1 [i]], он преобразует значение в строку из его первоначального значения, поэтому мы потеряли фактическое значение.
источник