Способы сравнения массивов js

JavaScript | Как найти различия в массивах?

Теоретическая часть вопроса

По сути нам нужно сравнить Наборы (Set) элементов двух Массивов(Array). Я специально создам массивы с повторяющимися значениями. Зачем? Потому что в реальной жизни скорее всего будут дубли элементов в пределах одного массива.

В решении этой задачи нас будут интересовать только САМИ ЗНАЧЕНИЯ, а не их последовательности. Сравнивать мы будем содержимое.

Наборы(Set) оставят нам уникальные значения в массивах, чтобы мы не повторяли процедуру переборов по несколько раз для одинаковых элементов массивов. Их может быть десятки тысяч в реальных проектах. Это нагрузка на систему.

Набор возвращает объект, а нам нужен массив. Конвертируем наборы в массивы:

Наборы из Массивов и обратно — JavaScript

Логика такая! Если значение из первого массива встречается во втором массиве, тогда идём дальше на следующий элемент. Если элементы совпадают — значит это не «РАЗЛИЧИЯ», а «ОДИНАКОВОСТИ».

Мы должны отобрать все различия и вернуть их в качестве отдельного массива. Эта операция похожа на «вычитание массивов» — элементы одного массива вычитаются из другого массива. Жаль, что для вычитания не придумали встроенного в язык метода, ходя для сложения он есть.

Решение

Будем использовать метод filter() прототипов объекта Array . Фильтр будет создавать нам новый массив. В качестве параметра будем передавать функцию, которая будет возвращаться нам булев тип данных — true или false. Фильтр будет смотреть на истину или ложь, и потом принимать решение сохранить этот элемент в новом массиве или нет.

И с этого момента у нас есть два пути решения задачи.

Способ № 1 — filter + includes

Логика работы includes возвращает нам истину, если находит элемент в массиве. Например, если filter кидает нам первый элемент первого массива (1), то includes будет искать его во втором массиве, а когда найдёт — вернёт true. filter в первую итерацию посмотрит на true и закинет значение 1 в новый массив. Такой вариант нам не подходит потому, что так мы получим набор общих элементов, которые встречаются и в первом, и во втором массивах.

Вернёт общие с первым набором элементы. Те из первого, которые встречаются во втором наборе.

Вернёт общие со вторым набором элементы. Те из второго, которые встречаются в первом наборе.

При любой вариации вернёт ОБЩИЕ элементы.

ВНИМАНИЕ! Но если мы добавим отрицание в работу метода includes() , то будем получать НУЖНЫЙ НАМ РЕЗУЛЬТАТ:

Вернёт элементы, которые не встречаются во втором наборе (массиве)

Вернёт элементы, которые не встречаются в первом наборе (массиве)

Отрицание includes — JavaScript

Можно сразу создать массив из элементов «РАЗНИЦЫ»:

Функция для работы

Разница между двумя массивами:

Разница между несколькими массивами:

Способ № 2 — filter + indexOf

Вернёт те, которых нет во втором

Вернёт те, которых нет в первом

Существует целое направление задач, таких как:

Они схожи по своему смыслу т. к. взаимодействуют со множествами.

Информационные ссылки

JavaScriptНаборы(Set)

Источник

Как сравнить массивы в JavaScript?

Я хотел бы сравнить два массива . в идеале, эффективно. Ничего особенного, просто true , если они идентичны, и false , если нет. Не удивительно, что оператор сравнения не работает.

JSON кодирует каждый массив, но есть ли более быстрый или «лучший» способ простого сравнения массивов без необходимости перебирать каждое значение?

28 ответов

Рекурсивно и работает с массивами NESTED :

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

Взгляните на мой код с вашим примером, который сравнивает два массива, элементы которых являются числами, вы можете изменить или расширить его для других типов элементов (используя .join () вместо .toString ()).

Опираясь на ответ Томаша Зато, я согласен, что итерация по массивам — самая быстрая. Кроме того (как уже говорили другие), функцию следует называть равной / равной, а не сравнивать. В свете этого я изменил функцию для обработки сравнения массивов на предмет сходства — то есть они имеют те же элементы, но не по порядку — для личного использования, и подумал, что я добавлю это здесь для всеобщего обозрения.

Читайте также:  Медный купорос способ применения для деревьев

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

Пример:

Я также написал быстрый jsfiddle с помощью функции и этого примера:
http://jsfiddle.net/Roundaround/DLkxX/

Непонятно, что вы подразумеваете под «тождественным». Например, совпадают ли массивы a и b ниже (обратите внимание на вложенные массивы)?

Вот оптимизированная функция сравнения массивов, которая сравнивает соответствующие элементы каждого массива по очереди, используя строгое равенство, и не выполняет рекурсивное сравнение элементов массива, которые сами являются массивами. Это означает, что для приведенного выше примера arraysIdentical(a, b) вернул бы <> . Он работает в общем случае, который решения на основе JSON и join() не будут:

Хотя это работает только для скалярных массивов (см. Примечание ниже), оно короткое:

Rr, в ECMAScript 6 / CoffeeScript / TypeScript с функциями стрелки:

(Примечание: здесь «скаляр» означает значения, которые можно сравнивать напрямую, используя === . Итак: числа, строки, объекты по ссылке, функции по ссылке. См. ссылка на MDN для получения дополнительной информации об операторах сравнения).

ОБНОВЛЕНИЕ

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

Тогда приведенный выше код даст true

Уже несколько хороших ответов. Но я хотел бы поделиться другой идеей, которая доказала свою надежность при сравнении массивов. Мы можем сравнить два массива, используя JSON .stringify () . Он создаст строку из массива и, таким образом, сравнит две полученные строки из двух массивов на равенство.

Расширение идеи Томаша Зато. Array.prototype.compare Томаса должен быть на самом деле Array.prototype.compareIdentical.

Но не получается:

Вот лучшая (на мой взгляд) версия:

Я верю в простую JS и ECMAScript 2015 , что приятно и просто для понимания.

Надеюсь, это кому-то поможет.

Мне нравится использовать библиотеку Underscore для проектов тяжелого кодирования массивов / объектов . в Underscore и Lodash, сравниваете ли вы массивы или объекты, это выглядит просто так:

Несмотря на то, что у этого есть много ответов, я полагаю, что это поможет:

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

Что происходит, так это то, что мы используем оператор распространения (. ) для объединения обоих массивов, а затем используем Set для устранения любых дубликатов. Если у вас есть это, вы можете сравнить их размеры, если все три массива имеют одинаковый размер, вы можете пойти.

Этот ответ также игнорирует порядок элементов , как я уже сказал, точная ситуация произошла со мной, поэтому, возможно, кто-то в такой же ситуации может оказаться здесь (как я).

Отвечая на вопрос Дмитрия Гринько: «Почему вы использовали оператор распространения (. ) здесь — . новый сет? Он не работает»

Рассмотрим этот код:

Чтобы работать с этим значением, вам нужно использовать некоторые свойства Set (см. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set ) . С другой стороны, когда вы используете этот код:

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

Это, я думаю, самый простой способ сделать это с помощью JSON stringify, и в некоторых ситуациях это может быть лучшим решением:

Это преобразует объекты a1 и a2 в строки, чтобы их можно было сравнивать. Порядок важен в большинстве случаев, поскольку для этого можно отсортировать объект с помощью алгоритма сортировки, показанного в одном из приведенных выше ответов.

Обратите внимание, что вы больше не сравниваете объект, а представляете строковое представление объекта. Это может быть не совсем то, что вы хотите.

Читайте также:  Таблетки дриптан способ применения

Если вы используете среду тестирования, такую как Mocha с библиотека утверждений Chai, вы можете использовать глубокое равенство для сравнения массивы.

Это должно возвратить true, только если массивы имеют равные элементы в соответствующих индексах.

Если они представляют собой два массива чисел или только строки, это быстрый однострочный

Вот как я это сделал.

Сравнивая 2 массива:

В духе оригинального вопроса:

Я хотел бы сравнить два массива . в идеале, эффективно . Ничего fancy , просто true, если они идентичны, и false, если нет.

Я проводил тесты производительности для некоторых из более простых предложений, предложенных здесь, со следующими результатами (от быстрого до медленного ) :

в то время как (67%) Тимом Дауном

каждый (69%) пользователем2782196

сократить (74%) по DEI

присоединиться и toString (78%) , авторы — Гайка Альенде и Вивек

Полугодовая строка (90%) . Автор Victor Palomo

stringify (100%) от radtek

Примечание . В приведенных ниже примерах предполагается, что массивы — это отсортированные одномерные массивы. .length сравнение было удалено для общего теста (добавьте a1.length === a2.length к любому из предложений, и вы получите повышение производительности

10%). Выберите любые решения, которые лучше всего подходят для вас, зная скорость и ограничения каждого из них.

Несвязанное примечание . Интересно, что люди получают от Джона Уэйнса за все удовольствие от триггера за совершенно законные ответы на этот вопрос.

Вот версия Typescript:

Некоторые тесты для мокко:

Это сравнивает 2 несортированных массива:

Для массива чисел попробуйте

Практический путь

Я думаю, что неправильно говорить, что конкретная реализация является «Правильным путем», если она только «правильная» («правильная») в отличие от «неправильного» решения. Решение Томаша — явное улучшение по сравнению со сравнением массивов на основе строк, но это не значит, что оно объективно «правильно». Что такое правильно ? Это самый быстрый? Это самый гибкий? Это легче всего понять? Это самый быстрый для отладки? Использует ли он наименьшее количество операций? Есть ли у него побочные эффекты? Ни одно решение не может быть лучшим из всех.

Томаш мог бы сказать, что его решение быстрое, но я бы сказал, что оно слишком сложное. Он пытается быть универсальным решением, которое работает для всех массивов, вложенных или нет. На самом деле, он даже принимает в качестве входных данных не только массивы, но все еще пытается дать «правильный» ответ.

Дженерики предлагают повторное использование

Мой ответ подойдет к проблеме по-другому. Я начну с общей процедуры arrayCompare , которая касается только перехода по массивам. Оттуда мы создадим другие наши основные функции сравнения, такие как arrayEqual и arrayDeepEqual , и т. Д.

На мой взгляд, лучший вид кода даже не нуждается в комментариях, и это не исключение. Здесь происходит так мало, что вы можете понять поведение этой процедуры практически без усилий. Конечно, некоторые синтаксисы ES6 могут показаться вам чуждыми, но это только потому, что ES6 является относительно новым.

Как предполагает тип, arrayCompare принимает функцию сравнения f и два входных массива xs и ys . По большей части все, что мы делаем, это вызываем f (x) (y) для каждого элемента во входных массивах. Мы возвращаем ранний false , если пользовательский f возвращает false , благодаря оценке && короткого замыкания. Так что да, это означает, что компаратор может прекратить итерацию на ранней стадии и предотвратить циклическое прохождение через остальную часть входного массива, когда это не нужно.

Строгое сравнение

Затем, используя нашу arrayCompare функцию, мы можем легко создавать другие функции, которые нам могут понадобиться. Начнем с элементарного arrayEqual .

Просто как тот. arrayEqual можно определить с помощью arrayCompare и функции компаратора, которая сравнивает a с b , используя === (для строгого равенства).

Обратите внимание, что мы также определяем equal как его собственную функцию. Это подчеркивает роль arrayCompare как функции высшего порядка для использования нашего компаратора первого порядка в контексте другого типа данных (Array).

Слабое сравнение

Мы могли бы так же легко определить arrayLooseEqual , используя вместо этого == . Теперь при сравнении 1 (Number) с ‘1’ (String) результат будет true …

Глубокое сравнение (рекурсивное)

Вы, наверное, заметили, что это только поверхностное сравнение. Конечно, решение Томаша — «Правильный путь ™», потому что оно подразумевает глубокое сравнение, верно?

Читайте также:  Алкоголь как способ расслабиться

Ну, наша arrayCompare процедура достаточно универсальна, чтобы использовать ее так, чтобы сделать тест на глубокое равенство быстрым…

Просто как тот. Мы строим глубокий компаратор, используя другую функцию более высокого порядка. На этот раз мы оборачиваем arrayCompare с помощью пользовательского компаратора, который проверяет, являются ли a и b массивами. Если это так, повторно примените arrayDeepCompare , в противном случае сравните a и b с указанным пользователем компаратором ( f ). Это позволяет нам отделить поведение глубокого сравнения от того, как мы на самом деле сравниваем отдельные элементы. То есть, как показано в примере выше, мы можем глубоко сравнить, используя equal , looseEqual или любой другой компаратор, который мы создаем.

Поскольку arrayDeepCompare карри, мы можем частично применить его, как и в предыдущих примерах

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

Сравнение объектов (пример)

А что если у вас есть массив объектов или что-то еще? Может быть, вы хотите считать эти массивы «равными», если каждый объект имеет одинаковое id значение…

Просто как тот. Здесь я использовал ванильные объекты JS, но этот тип компаратора мог бы работать для любого типа объекта; даже ваши пользовательские объекты. Решение Томаша должно быть полностью переработано для поддержки такого теста на равенство

Глубокий массив с объектами? Не проблема. Мы создали универсальные универсальные функции, поэтому они будут работать в самых разных случаях.

Произвольное сравнение (пример)

Или что, если вы хотите провести какое-то совершенно произвольное сравнение? Может быть, я хочу знать, больше ли каждый x , чем каждый y .

Меньше — больше

Вы можете видеть, что мы на самом деле делаем больше с меньшим количеством кода. В самом arrayCompare нет ничего сложного, и каждый из созданных нами пользовательских компараторов имеет очень простую реализацию.

С легкостью мы можем точно определить, как мы хотим, чтобы сравнивались два массива — мелкий, глубокий, строгий, свободный, какое-либо свойство объекта или какое-либо произвольное вычисление, или любая их комбинация — все с использованием одной процедуры , arrayCompare . Может быть, даже мечтать о RegExp компараторе! Я знаю, как дети любят эти регулярные выражения .

Это самый быстрый? Нет. Но это, вероятно, не должно быть либо. Если бы скорость была единственным показателем, используемым для измерения качества нашего кода, было бы выброшено много действительно хорошего кода — вот почему я называю этот подход Практическим способом . Или, может быть, быть более справедливым, A Практическим способом. Это описание подходит для этого ответа, потому что я не говорю, что этот ответ только практичен по сравнению с некоторым другим ответом; это объективно верно. Мы достигли высокой степени практичности с очень небольшим количеством кода, который очень легко рассуждать. Ни один другой код не может сказать, что мы не заработали это описание.

Это делает это «правильным» решением для вас? Вам решать вам . И никто другой не может сделать это для вас; только вы знаете, каковы ваши потребности. Почти во всех случаях я ценю простой, практичный и универсальный код перед умным и быстрым. То, что вы цените, может отличаться, поэтому выберите то, что вам подходит.

Редактировать

Мой старый ответ был больше сфокусирован на разложении arrayEqual на крошечные процедуры. Это интересное упражнение, но не самый лучший (самый практичный) способ решения этой проблемы. Если вам интересно, вы можете увидеть эту историю изменений.

Вот мое решение:

Работает с любой вложенной структурой данных и, очевидно, игнорирует методы объектов. Даже не думайте о расширении Object.prototype с помощью этого метода, когда я однажды попробовал это сделать, jQuery сломался;)

Для большинства массивов это все же быстрее, чем у большинства решений для сериализации. Это, вероятно, самый быстрый метод сравнения для массивов записей объектов.

Работает с аргументами MULTIPLE с массивами NESTED :

В тех же строках, что и в JSON.encode, используется join ().

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

Если порядок должен оставаться тем же, чем просто цикл, сортировка не требуется.

Источник

Оцените статью
Разные способы