hash all elements in A [iterate the array and insert the elements into a hash-set], then iterate B, and check for each element if it is in B or not. you can get average run time of O(|A|+|B|).
You cannot get sub-linear complexity, so this solution is optimal for average case analyzis, however, since hashing is not O(1) worst case, you might get bad worst-case performance.
EDIT:
If you don’t have enough space to store a hash set of elements in B, you might want to concider a probabilistic solution using bloom filters. The problem: there might be some false positives [but never false negative]. Accuracy of being correct increases as you allocate more space for the bloom filter.
The other solution is as you said, sort, which will be O(nlogn) time, and then use binary search for all elements in B on the sorted array.
For 3rd stage, you get same complexity: O(nlogn) with the same solution, it will take approximately double time then stage 2, but still O(nlogn)
EDIT2:
Note that instead of using a regular hash, sometimes you can use a trie [depands on your elements type], for example: for ints, store the number as it was a string, each digit will be like a character. with this solution, you get O(|B|*num_digits+|A|*num_digits) solution, where num_digits is the number of digits in your numbers [if they are ints]. Assuming num_digits is bounded with a finite size, you get O(|A|+|B|) worst case.
Теоретическая часть вопроса
По сути нам нужно сравнить Наборы (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))
Набор возвращает объект, а нам нужен массив. Конвертируем наборы в массивы:
Логика такая! Если значение из первого массива встречается во втором массиве, тогда идём дальше на следующий элемент. Если элементы совпадают — значит это не «РАЗЛИЧИЯ», а «ОДИНАКОВОСТИ».
Мы должны отобрать все различия и вернуть их в качестве отдельного массива. Эта операция похожа на «вычитание массивов» — элементы одного массива вычитаются из другого массива. Жаль, что для вычитания не придумали встроенного в язык метода, ходя для сложения он есть.
Решение
Будем использовать метод 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))
Можно сразу создать массив из элементов «РАЗНИЦЫ»:
[...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 Objects — https://tc39.es/ecma262/#sec-set-objects
ECMAScript — Living Standard — Array Objects — https://tc39.es/ecma262/#sec-array-objects
|
NNN7 9 / 9 / 10 Регистрация: 05.09.2013 Сообщений: 502 |
||||
|
1 |
||||
Работа с массивами в С++ . Поиск отличающихся элементов двух массивов17.04.2014, 22:31. Показов 2153. Ответов 15 Метки нет (Все метки)
Здравствуйте . Есть два массива :
Как заполнить массив элементами , которые отличают эти массивы между собой? ( то есть , это будет 3,5,6,9) Заранее спасибо!
0 |
|
7525 / 6391 / 2913 Регистрация: 14.04.2014 Сообщений: 27,832 |
|
|
17.04.2014, 22:37 |
2 |
|
Просматриваешь первый массив, сравниваешь a[i] с каждым b[j], если совпадений нет, то добавляешь в c.
0 |
|
NNN7 9 / 9 / 10 Регистрация: 05.09.2013 Сообщений: 502 |
||||
|
17.04.2014, 22:38 [ТС] |
3 |
|||
|
пробовал как-то так начать , но , думаю, это не то , что нужно
0 |
|
zss Модератор 13101 / 10373 / 6207 Регистрация: 18.12.2011 Сообщений: 27,749 |
||||
|
17.04.2014, 22:39 |
4 |
|||
|
Решение
1 |
|
NNN7 9 / 9 / 10 Регистрация: 05.09.2013 Сообщений: 502 |
||||
|
17.04.2014, 22:55 [ТС] |
5 |
|||
|
Спасибо , что отозвались . В принципе , я примерно так и писал , но не могу понять , как вывести конечный результат ?
или так нельзя? и можете , пожалуйста , объяснить , как записываются элементы в массив с ? c[k++]=a[i]; — что это означает ? что индекс прибавляется при каждой записи нового элемента массива а ? P.S : извините , что такие глупые вопросы задаю
0 |
|
7525 / 6391 / 2913 Регистрация: 14.04.2014 Сообщений: 27,832 |
|
|
17.04.2014, 22:59 |
6 |
|
notpresent, чтобы не просматривать оставшуюся часть массива, если совпадение обнаружено.
1 |
|
NNN7 9 / 9 / 10 Регистрация: 05.09.2013 Сообщений: 502 |
||||
|
17.04.2014, 23:02 [ТС] |
7 |
|||
|
то есть :
что-то всё равно не пойму , как этот флаг работает
0 |
|
7525 / 6391 / 2913 Регистрация: 14.04.2014 Сообщений: 27,832 |
|
|
17.04.2014, 23:05 |
8 |
|
Например совпадение обнаружено уже на первом элементе. Он делает break, чтобы выйти из цикла и потом смотрит на по notpresent был ли break или просто цикл закончился и ничего не нашли.
0 |
|
9 / 9 / 10 Регистрация: 05.09.2013 Сообщений: 502 |
|
|
17.04.2014, 23:18 [ТС] |
9 |
|
ну допустим , совпадение на 1-ом элементе , делаем break , а что дальше всё равно не пойму (( мы ж вроде с цикла не выходим , а переходим на следующие условие ? я так понимаю, что 2-е условие это будет if(a[i]!=b[j]) ?
0 |
|
7525 / 6391 / 2913 Регистрация: 14.04.2014 Сообщений: 27,832 |
|
|
17.04.2014, 23:21 |
10 |
|
break выведет из цикла по j, т. е. просмотр второго массива прервётся. А дальше будет переход к следующему элементу первого массива.
1 |
|
9 / 9 / 10 Регистрация: 05.09.2013 Сообщений: 502 |
|
|
17.04.2014, 23:23 [ТС] |
11 |
|
а как тогда будут проверятся остальные элементы 2-го массива ? если уже на 1-ом проверка прерывается?
0 |
|
7525 / 6391 / 2913 Регистрация: 14.04.2014 Сообщений: 27,832 |
|
|
17.04.2014, 23:25 |
12 |
|
Это не требуется по условию задачи. Если даже там есть совпадения, значения не имеет, т. к. уникальность элемента опровергнута.
1 |
|
NNN7 9 / 9 / 10 Регистрация: 05.09.2013 Сообщений: 502 |
||||
|
17.04.2014, 23:25 [ТС] |
13 |
|||
|
и как вывести результат ? вот так не выводится :
не пойму , как сложить результаты 2-х циклов в один массив
0 |
|
nmcf 7525 / 6391 / 2913 Регистрация: 14.04.2014 Сообщений: 27,832 |
||||
|
17.04.2014, 23:27 |
14 |
|||
|
Ну ясен пень.
1 |
|
NNN7 9 / 9 / 10 Регистрация: 05.09.2013 Сообщений: 502 |
||||
|
18.04.2014, 09:14 [ТС] |
15 |
|||
|
Ошибку понял , но всё равно не хочет выводить :
Добавлено через 9 часов 41 минуту
0 |
|
zss Модератор 13101 / 10373 / 6207 Регистрация: 18.12.2011 Сообщений: 27,749 |
||||
|
18.04.2014, 19:06 |
16 |
|||
|
Поправьте строки
Опечатка (Было написано i=5)
0 |
18 сент. 2020 г.
• 3 min read
В этой статье я решил поделиться с вами некими магическими ES6 подходами по решению распространенных задач по нахождению в JavaScript пересечения массивов, поиск непересекаемых значений массива, или объединение всех элементов.
Эти задачи очень распространенные, но, иногда, мы слишком мудрИм, решая их. В этой статье я поделюсь с вами элегантными решениями, как можно, используя filter и Set решить эти задачи в одну-дву строки кода.
Код
Для всех последующих примеров мы смоделируем общий пример двух массивов, которые будем использовать во всех примерах:
const arrayA = [1, 3, 4, 5];
const arrayB = [1, 2, 5, 6, 7];
А результатом этих операций будет let result. Давайте разберём концепцию каждой задачи на примере Диаграмм Венна, для более ясной визуализации.
Пересечение элементов двух массивов
Результатом поиска пересечения элементов, которые являются общими для каждого из двух массивов будет [1, 5].
let intersection = arrayA.filter(num => arrayB.includes(num));
Разница между массивами
В этом примере найдём разницу элементов между двумя массивами. То есть, нам нужно найти элементы, элементы из arrayA, которых нет в arrayB.
Результатом будет [3, 4].
let difference = arrayA.filter(num => !arrayB.includes(num));
Симметричная разница
В этом случае вы получите массив, содержащий все элементы массива arrayA, которые не содержатся в массиве arrayB, и, наоборот. Проще говоря — неповторяющиеся значение из противоположного массивов.
И результатом будет [2, 3, 4, 6, 7].
let difference = arrayA
.filter(num => !arrayB.includes(num))
.concat(arrayB.filter(num => !arrayA.includes(num)));
Объединение массивов
Операция слияния, или же, объединения двух массивов является самой простой из всех перечисленных. Результатом будет новый массив со всеми элементами из arrayA и arrayB, и будет выглядеть вот так [1, 2, 3, 4, 5, 6, 7].
let union = [...arrA, ...arrB];
Однако, при таком подходе, когда мы используем Spread-оператор, элементы, встречающиеся в каждом из массивов — дублируются. Потому, это не совсем эталонное слияние. Для получения только уникальных значений при объединении двух массивов, привернем к использованию Set:
let union = [...new Set([...arrayA, ...arrayB])];
Почему Set? Set — это JavaScript структуру, которая хранит только уникальные значения. И, если вы попытаетесь добавить с Set уже существующее значение, то оно будет проигнорировано. Потому, именно благодаря такому свойству мы и добиваемся удаления дубликатов в массиве JavaScript, используя объект Set.
JavaScript шагнул настолько далеко в своём стандартном ES6 функционале, благодаря чему, вы можете отказаться от многих компонентов или библиотек, типа jQuery, lodash, или underscore. И вы можете уменьшить код из такого:
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;
}
До одной-двух строк кода, как мы разбирали выше. И это выглядит круто!
Так же, дополнительно советую почитать статью по работе с массивами в JavaScript, а так же, работу с объектами и распространёнными задачами, связанными с этими структурами.
Всем привет.
Вопрос думаю понятен. Т.е. мне нужно такое:
let arr = [1,2,3],
arr2 = [2,8,3,1];
let arr3 = [8];
-
Вопрос заданболее трёх лет назад
-
287 просмотров
Пригласить эксперта
let arr = [1,2,3],
arr2 = [2,8,3,1],
arr3 = arr2.filter(x => ! arr.includes(x))
var array_diff = function (l, r) {
return l.filter(function (v) {
return r.indexOf(v) == -1;
});
};
var a1 = [1,2,3], a2 = [2,8,3,1];
var result = array_diff(a1, a2).concat(array_diff(a2, a1));
-
Показать ещё
Загружается…
26 мая 2023, в 08:08
130000 руб./за проект
26 мая 2023, в 08:05
10000 руб./за проект
26 мая 2023, в 07:52
100000 руб./за проект



Сообщение было отмечено NNN7 как решение





