Какой самый краткий и эффективный способ выяснить, содержит ли массив JavaScript значение?
Это единственный способ, которым я знаю, чтобы сделать это:
function contains(a, obj) {
for (var i = 0; i < a.length; i++) {
if (a[i] === obj) {
return true;
}
}
return false;
}
Есть ли лучший и более краткий способ сделать это?
Это очень тесно связано с вопросом переполнения стека. Лучший способ найти элемент в массиве JavaScript? который обращается к поиску объектов в массиве, используя indexOf
.
~[1,2,3].indexOf(4)
вернет 0, что будет оцениваться как ложь, тогда как~[1,2,3].indexOf(3)
вернет -3, что оценит как истину.~
это не то, что вы хотите использовать для преобразования в логическое значение, для этого вам нужно!
. Но в этом случае вы хотите проверить равенство с -1, чтобы функция могла заканчиватьсяreturn [1,2,3].indexOf(3) === -1;
~
двоичным кодом, она будет инвертировать каждый бит значения по отдельности.[1,2,3].indexOf(4)
самом деле вернет -1 . Как указал @mcfedr,~
является побитовым оператором NOT , см. ES5 11.4.8. Дело в том, что, поскольку двоичное представление-1
состоит только из 1, его дополнение есть0
, которое оценивается как ложное. Дополнение любого другого числа будет отличным от нуля, следовательно, истина. Итак,~
работает просто отлично и часто используется вместе сindexOf
.[[1,2],[3,4]].includes([3,4])
?Ответы:
Современные браузеры имеют
Array#includes
, что делает именно это и широко поддерживается всеми, кроме IE:Вы также можете использовать
Array#indexOf
, что является менее прямым, но не требует полифилов для устаревших браузеров.Многие фреймворки также предлагают похожие методы:
$.inArray(value, array, [fromIndex])
_.contains(array, value)
(также с псевдонимом_.include
и_.includes
)dojo.indexOf(array, value, [fromIndex, findLast])
array.indexOf(value)
array.indexOf(value)
findValue(array, value)
array.indexOf(value)
Ext.Array.contains(array, value)
_.includes(array, value, [from])
(_.contains
ранее 4.0.0)R.includes(value, array)
Обратите внимание, что некоторые платформы реализуют это как функцию, в то время как другие добавляют функцию в прототип массива.
источник
Array.include
что возвращает логическое значениеarray.indexOf(object) != -1
inArray
ужасное имя для функции, которая возвращает индекс элемента, и-1
если он не существует. Я ожидаю, что логическое значение будет возвращено.Обновление с 2019 года: Этот ответ с 2008 года (11 лет!) И не имеет отношения к современному использованию JS. Обещанное улучшение производительности было основано на тесте, сделанном в браузерах того времени. Это может не относиться к современным контекстам выполнения JS. Если вам нужно простое решение, ищите другие ответы. Если вам нужна лучшая производительность, оцените себя в соответствующих средах исполнения.
Как уже говорили другие, итерация по массиву, вероятно, является наилучшим способом, но было доказано, что убывающий
while
цикл является самым быстрым способом итерации в JavaScript. Поэтому вы можете переписать свой код следующим образом:Конечно, вы можете также расширить прототип Array:
И теперь вы можете просто использовать следующее:
источник
for (o in array)
который не следует делать при циклическом прохождении массива ...indexOf
возможно, но это «расширение JavaScript к стандарту ECMA-262; как таковое оно может отсутствовать в других реализациях стандарта».Пример:
AFAICS Microsoft не предлагает какой-то альтернативы этому, но вы можете добавить аналогичные функции для массивов в Internet Explorer (и других браузерах, которые не поддерживают
indexOf
), если хотите, как показывает быстрый поиск в Google (например, этот ).источник
ECMAScript 7 вводит
Array.prototype.includes
.Это можно использовать так:
Он также принимает необязательный второй аргумент
fromIndex
:В отличие от
indexOf
, который использует строгое сравнение равенства ,includes
сравнивает с использованием алгоритма равенства SameValueZero . Это означает, что вы можете определить, содержит ли массивNaN
:Кроме того, в отличие
indexOf
,includes
не пропускает отсутствующие индексы:В настоящее время это все еще черновик, но его можно заполнить, чтобы он работал во всех браузерах.
источник
Верхние ответы предполагают примитивные типы, но если вы хотите узнать, содержит ли массив объект с некоторой чертой, Array.prototype.some () - очень элегантное решение:
Хорошая вещь об этом - то, что итерация прерывается, когда элемент найден, таким образом, ненужные итерационные циклы избавлены.
Кроме того, он хорошо вписывается в
if
оператор, поскольку возвращает логическое значение:* Как отметил в комментарии jamess, на момент получения ответа, сентябрь 2018 года,
Array.prototype.some()
полностью поддерживается: таблица поддержки caniuse.comисточник
Arrow functions
в этом примере это не так хорошо поддерживается. Для получения более подробной информации смотрите здесь: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Допустим, вы определили массив следующим образом:
Ниже приведены три способа проверить, есть ли
3
там. Все они возвращают либоtrue
илиfalse
.Метод Native Array (начиная с ES2016) ( таблица совместимости )
Как пользовательский метод Array (до ES2016)
Простая функция
источник
Вот совместимая с JavaScript 1.6 реализация
Array.indexOf
:источник
[].indexOf
это сокращение дляArray.prototype.indexOf
. Мы, параноидальные защитники Javascript, избегаем расширения собственных прототипов любой ценой.[].indexOf
создается новый массив, а затем осуществляется доступindexOf
, в то времяArray.prototype.indexOf
как он напрямую обращается к прототипу?[].indexOf === Array.prototype.indexOf
(попробуйте в FireBug), но наоборот[].indexOf !== Array.indexOf
.Использование:
источник
x ? true : false
обычно излишним. Это здесь.array.indexOf(search) >= 0
уже логическое. Простоreturn array.indexOf(search) >= 0
.Расширение
Array
объекта JavaScript - очень плохая идея, потому что вы вводите новые свойства (ваши пользовательские методы) вfor-in
циклы, которые могут нарушать существующие сценарии. Несколько лет назад авторам библиотеки Prototype пришлось перестроить свою библиотечную реализацию, чтобы удалить именно такие вещи.Если вам не нужно беспокоиться о совместимости с другим JavaScript, работающим на вашей странице, воспользуйтесь этим, в противном случае, я бы порекомендовал более неловкое, но более безопасное автономное функциональное решение.
источник
Один лайнер:
источник
array.filter(e=>e==x).length > 0
эквивалентно,array.some(e=>e==x)
ноsome
более эффективноПодумав на секунду, если вы делаете этот вызов много раз, гораздо эффективнее использовать
ассоциативный массивMap для поиска с использованием хеш-функции.https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
источник
Я использую следующее:
источник
Array.prototype.some () был добавлен к стандарту ECMA-262 в 5-м издании
источник
contains = (a, obj) => a.some((element) => element === obj))
Надеемся, более быстрый двунаправленный
indexOf
/lastIndexOf
альтернативный2015
В то время как новый метод включает в себя очень хорошо, поддержка пока практически нулевая.
Давно я думал о том, как заменить медленные функции indexOf / lastIndexOf.
Эффективный путь уже найден, глядя на топовые ответы. Из них я выбрал
contains
функцию @Damir Zekic, которая должна быть самой быстрой. Но в нем также говорится, что показатели взяты с 2008 года и поэтому устарели.Я также предпочитаю
while
болееfor
, но не по определенной причине я закончил писать эту функцию с для цикла. Это также может быть сделано сwhile --
.Мне было любопытно, если итерация была бы намного медленнее, если я проверяю обе стороны массива, делая это. По-видимому, нет, и поэтому эта функция примерно в два раза быстрее, чем те, которые проголосовали сверху. Очевидно, что это также быстрее, чем родной. Это в реальной среде, где вы никогда не узнаете, находится ли искомое значение в начале или в конце массива.
Когда вы знаете, что вы только что выдвинули массив со значением, использование lastIndexOf остается, вероятно, лучшим решением, но если вам нужно перемещаться по большим массивам, и результат может быть везде, это может быть надежным решением для ускорения работы.
Двунаправленный indexOf / lastIndexOf
Тест производительности
http://jsperf.com/bidirectionalindexof
В качестве теста я создал массив с 100k записей.
Три запроса: в начале, в середине и в конце массива.
Я надеюсь, что вы также найдете это интересным и протестируете производительность.
Примечание. Как вы можете видеть, я немного изменил
contains
функцию, чтобы отразить выходные данные indexOf & lastIndexOf (так, в основном,true
сindex
иfalse
с-1
). Это не должно причинить вреда.Вариант прототипа массива
Функцию также можно легко изменить, чтобы она возвращала истину или ложь или даже объект, строку или что-то еще.
И вот
while
вариант:Как это возможно?
Я думаю, что простой расчет для получения отраженного индекса в массиве настолько прост, что он в два раза быстрее, чем выполнение реальной итерации цикла.
Вот сложный пример выполнения трех проверок за итерацию, но это возможно только при более длинных вычислениях, которые вызывают замедление кода.
http://jsperf.com/bidirectionalindexof/2
источник
Представление
Сегодня 2020.01.07 я выполняю тесты на MacO HighSierra 10.13.6 на Chrome v78.0.0, Safari v13.0.4 и Firefox v71.0.0 для 15 выбранных решений. Выводы
JSON
,Set
и удивительноfind
(К, N, О) является самым медленным на все браузерыincludes
(F) быстр только на хромеfor
(C, D) иindexOf
(G, H), достаточно быстры во всех браузерах на маленьких и больших массивах, поэтому, вероятно, они являются лучшим выбором для эффективного решения.for
(C, D, E) дают аналогичные результаты (~ 630 операций в секунду - но E на safari и firefox было 10- На 20% медленнее, чем C и D)Результаты
подробности
Я выполняю 2 теста: для массива с 10 элементами и для массива с 1 миллионом элементов. В обоих случаях мы помещаем искомый элемент в середину массива.
Показать фрагмент кода
Массив малый - 10 элементов
Вы можете выполнить тесты на своем компьютере ЗДЕСЬ
Массив большой - 1.000.000 элементов
Вы можете выполнить тесты на своем компьютере ЗДЕСЬ
источник
Если вы используете JavaScript 1.6 или новее (Firefox 1.5 или новее), вы можете использовать Array.indexOf . В противном случае, я думаю, вы получите что-то похожее на ваш оригинальный код.
источник
Возвращает индекс массива, если найден, или -1, если не найден
источник
Мы используем этот фрагмент (работает с объектами, массивами, строками):
Применение:
источник
Если вы неоднократно проверяете наличие объекта в массиве, возможно, вам стоит
contains(a, obj)
.источник
Решение, которое работает во всех современных браузерах:
Применение:
IE6 + решение:
Применение:
Зачем использовать
JSON.stringify
?Array.indexOf
иArray.includes
(а также большинство ответов здесь) сравнивают только по ссылке, а не по значению.бонус
Неоптимизированный однострочный ES6:
Примечание. Сравнение объектов по значению будет работать лучше, если ключи расположены в одном и том же порядке, поэтому для безопасности можно сначала отсортировать ключи с помощью пакета, подобного следующему: https://www.npmjs.com/package/sort-keys.
Обновлена
contains
функция с улучшенной оптимизацией. Спасибо, что указали на это.источник
includes
функцию с вашим предложением. Я запустил jsperf с моей функцией. Это примерно в 5 раз медленнее, чем включает Лодаш. Хотя lodash не сравнивается по значению и не может найти{a: 1}
в[{a: 1}]
. Я не знаю, делает ли это какая-нибудь библиотека. Но мне любопытно, есть ли более эффективный и не безумно сложный способ сделать это.contains([{ a: 1, b: 2 }], { b: 2, a: 1 })
потому что строковые объекты поддерживают порядок свойств.sort-keys
примечание внизуИспользуйте lodash это некоторая функция.
Это сжато, точно и имеет большую поддержку кроссплатформенности.
Принятый ответ даже не соответствует требованиям.
Требования: Рекомендовать наиболее краткий и эффективный способ выяснить, содержит ли массив JavaScript объект.
Принятый ответ:
Моя рекомендация:
Ноты:
$ .inArray отлично работает для определения, существует ли скалярное значение в массиве скаляров ...
... но вопрос явно требует эффективного способа определить, содержится ли объект в массиве.
Чтобы обрабатывать как скаляры, так и объекты, вы можете сделать это:
источник
У ECMAScript 6 есть элегантное предложение по поиску.
Вот документация MDN по этому вопросу.
Функциональность поиска работает следующим образом.
Вы можете использовать это в ECMAScript 5 и ниже, определив функцию .
источник
Хотя
array.indexOf(x)!=-1
это наиболее лаконичный способ сделать это (и поддерживается браузерами не Internet Explorer более десяти лет ...), это не O (1), а скорее O (N), что ужасно. Если ваш массив не изменится, вы можете преобразовать его в хеш-таблицу, затем выполнитеtable[x]!==undefined
или===undefined
:Демо-версия:
(К сожалению, хотя вы можете создать Array.prototype.contains для «замораживания» массива и сохранения хеш-таблицы в this._cache в две строки, это приведет к неверным результатам, если вы решите редактировать свой массив позже. У JavaScript недостаточно хуков для позвольте вам сохранить это состояние, в отличие от Python, например.)
источник
Можно использовать Set , у которого есть метод "has ()":
источник
return proxy.has(obj)
это намного чище, чем две строки с оператором if-else здесьfunction contains(arr, obj) { return new Set(arr).has(obj); }
Использование:
демонстрация
Чтобы точно знать, что
tilde
~
делать в этот момент, обратитесь к этому вопросу. Что делает тильда, когда она предшествует выражению? ,источник
ОК, вы можете просто оптимизировать свой код, чтобы получить результат!
Есть много способов сделать это, которые будут чище и лучше, но я просто хотел получить ваш паттерн и применить его
JSON.stringify
, просто сделайте что-то подобное в вашем случае:источник
contains([{ a: 1, b: 2 }], { b: 2, a: 1 })
потому что строковые объекты поддерживают порядок свойств.Отнюдь не лучший, но я просто проявил творческий подход и добавил в репертуар.
Не используйте это
источник
Удивлен, что к этому вопросу еще не добавлен последний синтаксис, добавив мои 2 цента.
Допустим, у нас есть массив Objects arrObj, и мы хотим найти в нем obj.
Array.prototype. indexOf -> (возвращает индекс или -1 ) обычно используется для поиска индекса элемента в массиве. Это также может быть использовано для поиска объекта, но работает, только если вы передаете ссылку на тот же объект.
Array.prototype. включает в себя -> (возвращает истину или ложь )
Array.prototype. find -> (принимает обратный вызов, возвращает первое значение / объект, который возвращает true в CB).
Array.prototype. findIndex -> (принимает обратный вызов, возвращает индекс первого значения / объекта, который возвращает true в CB).
Поскольку find и findIndex принимают обратный вызов, мы можем извлечь любой объект (даже если у нас нет ссылки) из массива, творчески установив истинное условие.
источник
Простое решение для этого требования использует
find()
Если у вас есть массив объектов, как показано ниже,
Затем вы можете проверить, присутствует ли объект с вашим значением или нет
если data имеет значение null, то нет администратора, иначе он вернет существующий объект, как показано ниже.
Затем вы можете найти индекс этого объекта в массиве и заменить объект, используя приведенный ниже код.
вы получите значение, как показано ниже
надеюсь, это кому-нибудь поможет.
источник
источник