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

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

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

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

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

var massiv1 = [1,2,3,3,4,4,4,5,6,7,8,9,9]
var massiv2 = [1,1,3,3,4,4,4,6,6,7,8,10,11]

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

var set1 = Array.from(new Set(massiv1))
var set2 = Array.from(new Set(massiv2))

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

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

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

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

 

Решение

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

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

 

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

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

 

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

var filter1 = set1.filter(i => set2.includes(i))

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

var filter2 = set2.filter(i => set1.includes(i))

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

[1, 3, 4, 6, 7, 8]

 

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

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

var test1 = set1.filter(i => !set2.includes(i))

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

var test2 = set2.filter(i => !set1.includes(i))
Отрицание includes - JavaScript
Отрицание includes — JavaScript

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

[...set1.filter(i => !set2.includes(i)), ...set2.filter(i => !set1.includes(i))]

 

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

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

function arrayDiff(a, b) {
   return [
      ...a.filter(x => !b.includes(x)),
      ...b.filter(x => !a.includes(x))
   ];
}

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

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

 

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

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

var fil1 = set1.filter(i => set2.indexOf(i) < 0)
[2, 5, 9]

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

var fil2 = set2.filter(i => set1.indexOf(i) < 0)
[10, 11]

 

Итог

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

  • объединение
  • пересечение
  • разность

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

 

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

JavaScriptМассивы(Array)https://efim360.ru/javascript-massivy-array/

JavaScriptНаборы(Set)

ECMAScript — Living Standard — Set Objectshttps://tc39.es/ecma262/#sec-set-objects

ECMAScript — Living Standard — Array Objectshttps://tc39.es/ecma262/#sec-array-objects