Какой самый простой, свободный от библиотек код для реализации пересечений массивов в javascript? Я хочу написать
intersection([1,2,3], [2,3,4,5])
и получить
[2, 3]
Какой самый простой, свободный от библиотек код для реализации пересечений массивов в javascript? Я хочу написать
intersection([1,2,3], [2,3,4,5])
и получить
[2, 3]
break
кSimple js loops
увеличивает число операций в секунду до ~ 10MОтветы:
Используйте комбинацию
Array.prototype.filter
иArray.prototype.indexOf
:Или, как предложил Вругтехагель в комментариях, вы можете использовать более свежую версию
Array.prototype.includes
для еще более простого кода:Для старых браузеров:
источник
intersection([1,2,1,1,3], [1])
возвращается[1, 1, 1]
. Разве это не должно вернуться просто[1]
?array2.indexOf(n) != -1
можно также написатьarray2.includes(n)
для еще более простого кода.Деструктивный кажется самым простым, особенно если мы можем предположить, что вход отсортирован:
Неразрушающий должен быть более сложным, так как мы должны отслеживать показатели:
источник
intersect_safe
:length
это свойство в массивах, а не метод. Есть незадействованная переменнаяi
вresult.push(a[i]);
. Наконец, это просто не работает в общем случае: два объекта, где ни один не больше другого согласно>
оператору, не обязательно равны.intersect_safe( [ {} ], [ {} ] )
например, даст (после исправления ранее упомянутых ошибок) массив с одним элементом, что явно неверно..slice(0)
для создания клона массиваintersect_safe
, а не отслеживания индексов.Если ваша среда поддерживает набор ECMAScript 6 , один простой и предположительно эффективный (см. Ссылку на спецификацию) способ:
Короче, но менее читабельно (также без создания дополнительного пересечения
Set
):Избежать новое
Set
отb
каждого времени:Обратите внимание, что при использовании наборов вы получите только различные значения, поэтому
new Set[1,2,3,3].size
оцените их3
.источник
[...setA]
синтаксис? Какой-то особый вид работы с JavaScript?x => new Set(b).has(x)
функция стрелки не превращаетсяb
в набор каждый раз, когда она выполняется? Вы, вероятно, должны сохранить этот набор в переменной.Использование Underscore.js или lodash.js
источник
Мой вклад в терминах ES6. В общем случае он находит пересечение массива с неопределенным числом массивов, предоставляемых в качестве аргументов.
источник
[[0,1,2,3,4,5,6,7,8,9],[0,2,4,6,8],[4,5,6,7],[4,6]]
и затем применяется.reduce()
. Первая[0,1,2,3,4,5,6,7,8,9].filter( e => [0,2,4,6,8].includes(e)
операция выполняется , и результат становится новымp
иc
становится[4,5,6,7]
в следующем повороте и продолжает так далее вверх до тех пор, пока больше неc
осталось.prototype
излишне.Я рекомендую выше краткое решение, которое превосходит другие реализации на больших входах. Если производительность на небольших входах имеет значение, проверьте альтернативы ниже.
Альтернативы и сравнение производительности:
Посмотрите следующий фрагмент для альтернативных реализаций и проверьте https://jsperf.com/array-intersection-comparison для сравнения производительности.
Показать фрагмент кода
Результаты в Firefox 53:
Операций в секунду на больших массивах (10 000 элементов):
Операций в секунду на небольших массивах (100 элементов):
источник
intersect([1,2,2,3], [2,3,4,5])
возвращается[2, 2, 3]
.a.filter(b.includes)
. Он должен работать значительно быстрее (так же, как обновление вашей функции).Как насчет использования ассоциативных массивов?
редактировать:
источник
Object.prototype
.d[b[i]] = true;
вместоd[b[j]] = true;
(i
нетj
). Но редактирование требует 6 символов.Как-то так, не проверено хорошо, хотя.
PS: алгоритм предназначен только для чисел и нормальных строк, пересечение массивов произвольных объектов может не работать.
источник
Производительность реализации @ atk для отсортированных массивов примитивов можно улучшить, используя .pop, а не .shift.
Я создал тест, используя jsPerf: http://bit.ly/P9FrZK . Это примерно в три раза быстрее .pop.
источник
a[aLast] > b[bLast]
сa[aLast].localeCompare(b[bLast]) > 0
(и то же самое сelse if
ниже) , то это будет работать на струнах..pop
это O (1) и.shift()
O (n)Используя jQuery :
источник
c = $(b).filter(a);
, но я бы не рекомендовал полагаться на jQuery для такого рода манипуляций с массивами, поскольку в документации упоминается только то, что это работает для элементов.Для массивов, содержащих только строки или числа, вы можете сделать что-то с сортировкой, как в некоторых других ответах. Для общего случая массивов произвольных объектов, я не думаю, что вы можете избежать этого. Следующее даст вам пересечение любого количества массивов, предоставленных в качестве параметров для
arrayIntersection
:источник
firstArr
илиfirstArray
не обновил все ссылки. Исправлена.Это довольно коротко, используя ES2015 и Sets. Принимает подобные массиву значения, такие как String, и удаляет дубликаты.
источник
Вы могли бы использовать в
Set
качествеthisArg
изArray#filter
и взять вSet#has
качестве обратного вызова.источник
Небольшая настройка на самое маленькое здесь (решение filter / indexOf ), а именно создание индекса значений в одном из массивов с использованием объекта JavaScript, уменьшит его с O (N * M) до «вероятно» линейного времени. источник1 источник2
Это не самое простое решение (это больше кода, чем filter + indexOf ), и при этом оно не является самым быстрым (вероятно, медленнее на постоянный коэффициент, чем intersect_safe () ), но кажется довольно хорошим балансом. Он очень прост и обеспечивает хорошую производительность и не требует предварительно отсортированных входных данных.
источник
Еще один индексированный подход, способный обрабатывать любое количество массивов одновременно:
Он работает только для значений, которые могут быть оценены как строки, и вы должны передать их как массив, например:
... но он прозрачно принимает объекты как параметр или как любой из элементов, которые должны быть пересечены (всегда возвращает массив общих значений). Примеры:
РЕДАКТИРОВАТЬ: я только заметил, что это, в некотором смысле, немного глючит.
То есть: я кодировал его, думая, что входные массивы не могут содержать повторения (как в приведенном примере этого не происходит).
Но если входные массивы содержат повторения, это приведет к неверным результатам. Пример (используя приведенную ниже реализацию):
К счастью, это легко исправить, просто добавив индексирование второго уровня. Это:
Изменить:
по:
...а также:
по:
Полный пример:
источник
var v =
строки добавитьif (typeof v == 'function') continue;
и пропустить добавление функций к результатам. Спасибо!if (typeof v == 'function')
, тогда мы можем использовать его stringification (v.toString()
) в качестве ключа для индекса. Но нам нужно что-то сделать, чтобы сохранить его в целости. Самый простой способ сделать это - просто назначить исходную функцию как значение вместо простого логического истинного значения, но в этом случае следует также изменить последний деиндексат, чтобы обнаружить это условие и восстановить правильное значение (функцию).Вы можете использовать (для всех браузеров, кроме IE):
или для IE:
источник
источник
С некоторыми ограничениями на ваши данные, вы можете сделать это за линейное время!
Для натуральных чисел : используйте массив, отображающий значения в логическое значение «видел / не видел».
Для объектов существует аналогичная техника : возьмите фиктивный ключ, установите его в «true» для каждого элемента в массиве array1, затем ищите этот ключ в элементах array2. Вымойтесь, когда закончите.
Конечно, вы должны быть уверены, что ключ не появлялся раньше, иначе вы уничтожите свои данные ...
источник
Я внесу свой вклад в то, что получилось лучше для меня:
источник
"indexOf" для IE 9.0, Chrome, Firefox, Opera,
источник
источник
Функциональный подход с ES2015
Функциональный подход должен предусматривать использование только чистых функций без побочных эффектов, каждая из которых связана только с одной работой.
Эти ограничения улучшают компоновку и возможность повторного использования задействованных функций.
Обратите внимание, что используется нативный
Set
тип, который имеет полезную производительность поиска.Избегайте дубликатов
Очевидно, многократно встречающиеся элементы первого
Array
сохраняются, а второйArray
дедуплицируется. Это может быть или не быть желаемым поведением. Если вам нужен уникальный результат, просто применитеdedupe
к первому аргументу:Вычислить пересечение любого числа
Array
сЕсли вы хотите вычислить пересечение произвольного числа
Array
s, просто составьтеintersect
сfoldl
. Вот удобная функция:источник
(expr ? true : false)
это избыточно. Используйте толькоexpr
если фактические логические значения не нужны, просто истина / ложь.Для простоты:
Льготы:
Недостатки:
Вы не захотите использовать это для работы с трехмерным движком или ядром, но если у вас есть проблемы с его запуском в приложении, основанном на событиях, у вашего дизайна большие проблемы.
источник
.reduce
построить карту и.filter
найти пересечение.delete
в пределах.filter
позволяет нам рассматривать второй массив как уникальный набор.Я нахожу этот подход довольно легко рассуждать. Работает в постоянном времени.
источник
Это, вероятно, самый простой способ , кроме list1.filter (n => list2.include (n))
источник
Если вам нужно, чтобы он обрабатывал пересекающиеся несколько массивов:
источник
Стиль ES6 простой способ.
Пример:
источник
Я написал функцию пересечения, которая может даже обнаружить пересечение массива объектов на основе конкретного свойства этих объектов.
Например,
и мы хотим пересечение на основе
id
свойства, то результат должен быть:Также, функция для того же самого (примечание: код ES6):
и вы можете вызвать функцию как:
Также обратите внимание: эта функция находит пересечение, учитывая, что первый массив является первичным массивом, и, таким образом, результатом пересечения будет результат первичного массива.
источник
Думаю, это будет быстрее, если время O (array1 + array2) при условии, что map.has () равно ~ O (1). Пожалуйста, исправьте меня, если ошиблись.
источник
Вот реализация underscore.js :
Источник: http://underscorejs.org/docs/underscore.html#section-62
источник