Как проверить, содержит ли массив значение в JavaScript?


4002

Какой самый краткий и эффективный способ выяснить, содержит ли массив JavaScript значение?

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

function contains(a, obj) {
    for (var i = 0; i < a.length; i++) {
        if (a[i] === obj) {
            return true;
        }
    }
    return false;
}

Есть ли лучший и более краткий способ сделать это?

Это очень тесно связано с вопросом переполнения стека. Лучший способ найти элемент в массиве JavaScript? который обращается к поиску объектов в массиве, используя indexOf.


49
только что протестировал: ваш путь на самом деле самый быстрый для всех браузеров: jsperf.com/find-element-in-obj-vs-array/2 (кроме предварительного сохранения a.length в переменной) при использовании indexOf (как в $ .inArray) намного медленнее
— Йорн Беркефельд

17
многие ответили, что Array # indexOf - ваш лучший выбор здесь. Но если вы хотите что-то, что может быть правильно приведено к Boolean, используйте это: ~[1,2,3].indexOf(4)вернет 0, что будет оцениваться как ложь, тогда как ~[1,2,3].indexOf(3)вернет -3, что оценит как истину.
— Lordvlad

8
~это не то, что вы хотите использовать для преобразования в логическое значение, для этого вам нужно !. Но в этом случае вы хотите проверить равенство с -1, чтобы функция могла заканчиваться return [1,2,3].indexOf(3) === -1; ~двоичным кодом, она будет инвертировать каждый бит значения по отдельности.
— mcfedr

14
@Iordvlad на [1,2,3].indexOf(4)самом деле вернет -1 . Как указал @mcfedr, ~является побитовым оператором NOT , см. ES5 11.4.8. Дело в том, что, поскольку двоичное представление -1состоит только из 1, его дополнение есть 0, которое оценивается как ложное. Дополнение любого другого числа будет отличным от нуля, следовательно, истина. Итак, ~работает просто отлично и часто используется вместе с indexOf.
— mknecht

5
Название вводит в заблуждение. Где находится [[1,2],[3,4]].includes([3,4])?
— mplungjan

Ответы:


4381

Современные браузеры имеют Array#includes, что делает именно это и широко поддерживается всеми, кроме IE:

console.log(['joe', 'jane', 'mary'].includes('jane')); //true

Вы также можете использовать Array#indexOf, что является менее прямым, но не требует полифилов для устаревших браузеров.


Многие фреймворки также предлагают похожие методы:

Обратите внимание, что некоторые платформы реализуют это как функцию, в то время как другие добавляют функцию в прототип массива.


42
MooTools также имеет Array.contains, который возвращает логическое значение, которое здесь звучит как настоящий вопрос.
— Райан Флоренс

22
Прототип также имеет, Array.includeчто возвращает логическое значение
— user102008

46
Если вы используете хороший браузер, вы можете просто использоватьarray.indexOf(object) != -1
— Сэм Соффс

13
Кроме того, не используйте в качестве условия только indexOf, поскольку первый элемент вернет 0 и будет оценен как ложный
— плюс

241
inArrayужасное имя для функции, которая возвращает индекс элемента, и -1если он не существует. Я ожидаю, что логическое значение будет возвращено.
— Тим

434

Обновление с 2019 года: Этот ответ с 2008 года (11 лет!) И не имеет отношения к современному использованию JS. Обещанное улучшение производительности было основано на тесте, сделанном в браузерах того времени. Это может не относиться к современным контекстам выполнения JS. Если вам нужно простое решение, ищите другие ответы. Если вам нужна лучшая производительность, оцените себя в соответствующих средах исполнения.

Как уже говорили другие, итерация по массиву, вероятно, является наилучшим способом, но было доказано, что убывающий whileцикл является самым быстрым способом итерации в JavaScript. Поэтому вы можете переписать свой код следующим образом:

function contains(a, obj) {
    var i = a.length;
    while (i--) {
       if (a[i] === obj) {
           return true;
       }
    }
    return false;
}

Конечно, вы можете также расширить прототип Array:

Array.prototype.contains = function(obj) {
    var i = this.length;
    while (i--) {
        if (this[i] === obj) {
            return true;
        }
    }
    return false;
}

И теперь вы можете просто использовать следующее:

alert([1, 2, 3].contains(2)); // => true
alert([1, 2, 3].contains('2')); // => false


22
«Проверено» - это сильное слово. Двигатели JS постоянно совершенствуются, а время выполнения, измеренное 3 года назад, ужасно устарело.
— orip

2
@ Дамир - я согласен. Возможно, измените пример, чтобы использовать indexOf, если он доступен, просто чтобы люди, слепо копирующие этот код, получали максимальную производительность, какую только могли.
— orip

1
@cbmeeks да, забота определенно необходима. Вероятно, это был случай, for (o in array)который не следует делать при циклическом прохождении массива ...
— Дамир Зекич

1
Лучший способ сделать это - проверить, если [1, 2, 3] .indexOf (1)> -1
— Devin G Rhode

207

indexOf возможно, но это «расширение JavaScript к стандарту ECMA-262; как таковое оно может отсутствовать в других реализациях стандарта».

Пример:

[1, 2, 3].indexOf(1) => 0
["foo", "bar", "baz"].indexOf("bar") => 1
[1, 2, 3].indexOf(4) => -1

AFAICS Microsoft не предлагает какой-то альтернативы этому, но вы можете добавить аналогичные функции для массивов в Internet Explorer (и других браузерах, которые не поддерживают indexOf), если хотите, как показывает быстрый поиск в Google (например, этот ).


на самом деле, есть пример реализации расширения indexOf для браузеров, которые не поддерживают его, на странице developer.mozilla.org, на которую вы ссылаетесь.
— Ллойд Коттен

на самом деле, если вы добавите indexof к прототипу Array для браузеров, которые его не поддерживают (т.е. IE7), они также попытаются перебрать эту функцию при циклическом просмотре элементов в массиве. противно.
— CpILL


это применимо для проверки на предмет? я не думаю, что это работает в случае Объекта
— Химеш Аадесхара

169

ECMAScript 7 вводит Array.prototype.includes.

Это можно использовать так:

[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false

Он также принимает необязательный второй аргумент fromIndex:

[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true

В отличие от indexOf, который использует строгое сравнение равенства , includesсравнивает с использованием алгоритма равенства SameValueZero . Это означает, что вы можете определить, содержит ли массив NaN:

[1, 2, NaN].includes(NaN); // true

Кроме того, в отличие indexOf, includesне пропускает отсутствующие индексы:

new Array(5).includes(undefined); // true

В настоящее время это все еще черновик, но его можно заполнить, чтобы он работал во всех браузерах.


3
Не поддерживается для IE и Microsfot Edge (2015) ( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… )
— Адриано Резенде,

1
Также имеет значение таблица совместимости ES7 (похоже, что Chrome поддерживает ее сейчас)
— стиль

это применимо для проверки на предмет? я не думаю, что это работает в случае Объекта
— Химеш Аадесхара

128

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

const items = [ {a: '1'}, {a: '2'}, {a: '3'} ]

items.some(item => item.a === '3')  // returns true
items.some(item => item.a === '4')  // returns false

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

Кроме того, он хорошо вписывается в ifоператор, поскольку возвращает логическое значение:

if (items.some(item => item.a === '3')) {
  // do something
}

* Как отметил в комментарии jamess, на момент получения ответа, сентябрь 2018 года, Array.prototype.some()полностью поддерживается: таблица поддержки caniuse.com


1
На сегодняшний день, сентябрь 2018 года, Array.prototype.some () полностью поддерживается: таблица поддержки
— caniuse.com

1
Работа в Node> = 8.10 для AWS Node.js Lambda, так что это здорово. Очень чистое и простое решение! J
— Иордания

1
@jamess Это может быть хорошо поддержано, но помните, что Arrow functionsв этом примере это не так хорошо поддерживается. Для получения более подробной информации смотрите здесь: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
— Камил Витковски

Есть ли какое-нибудь короткое замыкание? Или он повторяет весь массив, даже если он нашел значение?
— Дуглас Гаскелл

@DouglasGaskell прерывает итерацию, найденную (упомянуто в ответе)
— Майкл

112

Допустим, вы определили массив следующим образом:

const array = [1, 2, 3, 4]

Ниже приведены три способа проверить, есть ли 3там. Все они возвращают либо trueили false.

Метод Native Array (начиная с ES2016) ( таблица совместимости )

array.includes(3) // true

Как пользовательский метод Array (до ES2016)

// Prefixing the method with '_' to avoid name clashes
Object.defineProperty(Array.prototype, '_includes', { value: function (v) { return this.indexOf(v) !== -1 }})
array._includes(3) // true

Простая функция

const includes = (a, v) => a.indexOf(v) !== -1
includes(array, 3) // true

Он возвращает true, если "b" находится в массиве "a" ... Я не знаю, как еще это объяснить ...
— Уильям Мало

4
Эту часть я не понимаю "!! ~". И я думаю, что это не будет работать в IE8, потому что IE8 не поддерживает indexOf () для объекта Array.
— свида

62
«~» - оператор, который вычитает, инвертирует и вычитает 1 из числа. indexOf возвращает -1 в случае неудачи, поэтому «~» превращает -1 в «0». с помощью "!!" витки номера в boleans (!! 0 === ложь)
— уилльям Malo

1
Круто, но серьезно ради простоты у не только a.indexOf (b)> - 1, так как "> -1" .length === "!! ~" .length
— супер

2
Я бы назвал отсутствие знаний о влиянии логических операторов непрофессиональным. Но я согласен с ценностью читабельного кода, я бы наверняка обернул это в четко обозначенную функцию. И это именно то, что делают большинство основных JS-фреймворков.
— okdewit

79

Вот совместимая с JavaScript 1.6 реализация Array.indexOf:

if (!Array.indexOf) {
    Array.indexOf = [].indexOf ?
        function(arr, obj, from) {
            return arr.indexOf(obj, from);
        } :
        function(arr, obj, from) { // (for IE6)
            var l = arr.length,
                i = from ? parseInt((1 * from) + (from < 0 ? l : 0), 10) : 0;
            i = i < 0 ? 0 : i;
            for (; i < l; i++) {
                if (i in arr && arr[i] === obj) {
                    return i;
                }
            }
            return -1;
        };
}

Это выглядит великолепно, но немного запутанно: * Разве тесты в строках 1 и 3 не эквивалентны? * Не лучше ли протестировать прототип и, если необходимо, добавить функцию в Array.prototype?
— Ави Лен

10
Они не эквивалентны. [].indexOfэто сокращение для Array.prototype.indexOf. Мы, параноидальные защитники Javascript, избегаем расширения собственных прототипов любой ценой.
— Мар Эрлигссон

1
Разве не [].indexOfсоздается новый массив, а затем осуществляется доступ indexOf, в то время Array.prototype.indexOfкак он напрямую обращается к прототипу?
— Алекс

3
@alex да [].indexOf === Array.prototype.indexOf(попробуйте в FireBug), но наоборот [].indexOf !== Array.indexOf.
— Мар Örlygsson

57

Использование:

function isInArray(array, search)
{
    return array.indexOf(search) >= 0;
}

// Usage
if(isInArray(my_array, "my_value"))
{
    //...
}

25
x ? true : falseобычно излишним. Это здесь.
— Ry-

@minitech Почему вы говорите, что это избыточно?
— Матиас Канепа

8
array.indexOf(search) >= 0уже логическое. Просто return array.indexOf(search) >= 0.
— Ry-

@minitech хорошо, спасибо! На самом деле я не знал, что такая конструкция может быть возвращена. Пока что-то новое.
— Матиас Канепа

Буквально любая конструкция в javascript может быть возвращена
— BT

49

Расширение Arrayобъекта JavaScript - очень плохая идея, потому что вы вводите новые свойства (ваши пользовательские методы) в for-inциклы, которые могут нарушать существующие сценарии. Несколько лет назад авторам библиотеки Prototype пришлось перестроить свою библиотечную реализацию, чтобы удалить именно такие вещи.

Если вам не нужно беспокоиться о совместимости с другим JavaScript, работающим на вашей странице, воспользуйтесь этим, в противном случае, я бы порекомендовал более неловкое, но более безопасное автономное функциональное решение.


22
Я не согласен. По этой причине циклы for-in не должны использоваться для массивов. Использование циклов for-in прекратится при использовании одной из популярных библиотек js
— Томас

Будет ли это считаться исправлением обезьяны? LOL Некоторые люди, как это.
— cbmeeks

33

Один лайнер:

function contains(arr, x) {
    return arr.filter(function(elem) { return elem == x }).length > 0;
}

8
array.filter(e=>e==x).length > 0эквивалентно, array.some(e=>e==x)но someболее эффективно
— Аполо

32

Подумав на секунду, если вы делаете этот вызов много раз, гораздо эффективнее использовать ассоциативный массив Map для поиска с использованием хеш-функции.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map


Хотя это очевидно полезно для многих, было бы лучше, если бы был добавлен фрагмент кода.
— Пирог «О» Пах

28

Я использую следующее:

Array.prototype.contains = function (v) {
    return this.indexOf(v) > -1;
}

var a = [ 'foo', 'bar' ];

a.contains('foo'); // true
a.contains('fox'); // false


19

Надеемся, более быстрый двунаправленный indexOf/ lastIndexOfальтернативный

2015

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

Давно я думал о том, как заменить медленные функции indexOf / lastIndexOf.

Эффективный путь уже найден, глядя на топовые ответы. Из них я выбрал containsфункцию @Damir Zekic, которая должна быть самой быстрой. Но в нем также говорится, что показатели взяты с 2008 года и поэтому устарели.

Я также предпочитаю whileболее for, но не по определенной причине я закончил писать эту функцию с для цикла. Это также может быть сделано с while --.

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

Когда вы знаете, что вы только что выдвинули массив со значением, использование lastIndexOf остается, вероятно, лучшим решением, но если вам нужно перемещаться по большим массивам, и результат может быть везде, это может быть надежным решением для ускорения работы.

Двунаправленный indexOf / lastIndexOf

function bidirectionalIndexOf(a, b, c, d, e){
  for(c=a.length,d=c*1; c--; ){
    if(a[c]==b) return c; //or this[c]===b
    if(a[e=d-1-c]==b) return e; //or a[e=d-1-c]===b
  }
  return -1
}

//Usage
bidirectionalIndexOf(array,'value');

Тест производительности

http://jsperf.com/bidirectionalindexof

В качестве теста я создал массив с 100k записей.

Три запроса: в начале, в середине и в конце массива.

Я надеюсь, что вы также найдете это интересным и протестируете производительность.

Примечание. Как вы можете видеть, я немного изменил containsфункцию, чтобы отразить выходные данные indexOf & lastIndexOf (так, в основном, trueс indexи falseс -1). Это не должно причинить вреда.

Вариант прототипа массива

Object.defineProperty(Array.prototype,'bidirectionalIndexOf',{value:function(b,c,d,e){
  for(c=this.length,d=c*1; c--; ){
    if(this[c]==b) return c; //or this[c]===b
    if(this[e=d-1-c] == b) return e; //or this[e=d-1-c]===b
  }
  return -1
},writable:false, enumerable:false});

// Usage
array.bidirectionalIndexOf('value');

Функцию также можно легко изменить, чтобы она возвращала истину или ложь или даже объект, строку или что-то еще.

И вот whileвариант:

function bidirectionalIndexOf(a, b, c, d){
  c=a.length; d=c-1;
  while(c--){
    if(b===a[c]) return c;
    if(b===a[d-c]) return d-c;
  }
  return c
}

// Usage
bidirectionalIndexOf(array,'value');

Как это возможно?

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

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

http://jsperf.com/bidirectionalindexof/2


18

Представление

Сегодня 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, О) является самым медленным на все браузеры
  • es6 includes(F) быстр только на хроме
  • Решения, основанные на for(C, D) и indexOf(G, H), достаточно быстры во всех браузерах на маленьких и больших массивах, поэтому, вероятно, они являются лучшим выбором для эффективного решения.
  • Решения, где индекс уменьшается во время цикла, (B) медленнее, вероятно, потому, что работает кеш процессора .
  • Я также запускаю тест для большого массива, когда искомый элемент находился в позиции 66% длины массива, и решения на основе for(C, D, E) дают аналогичные результаты (~ 630 операций в секунду - но E на safari и firefox было 10- На 20% медленнее, чем C и D)

Результаты

введите описание изображения здесь

подробности

Я выполняю 2 теста: для массива с 10 элементами и для массива с 1 миллионом элементов. В обоих случаях мы помещаем искомый элемент в середину массива.

Массив малый - 10 элементов

Вы можете выполнить тесты на своем компьютере ЗДЕСЬ

введите описание изображения здесь

Массив большой - 1.000.000 элементов

Вы можете выполнить тесты на своем компьютере ЗДЕСЬ

введите описание изображения здесь


лолз, это так долго
— да кокосовый орех

16

Если вы используете JavaScript 1.6 или новее (Firefox 1.5 или новее), вы можете использовать Array.indexOf . В противном случае, я думаю, вы получите что-то похожее на ваш оригинальный код.


16
function inArray(elem,array)
{
    var len = array.length;
    for(var i = 0 ; i < len;i++)
    {
        if(array[i] == elem){return i;}
    }
    return -1;
} 

Возвращает индекс массива, если найден, или -1, если не найден


16

Мы используем этот фрагмент (работает с объектами, массивами, строками):

/*
 * @function
 * @name Object.prototype.inArray
 * @description Extend Object prototype within inArray function
 *
 * @param {mix}    needle       - Search-able needle
 * @param {bool}   searchInKey  - Search needle in keys?
 *
 */
Object.defineProperty(Object.prototype, 'inArray',{
    value: function(needle, searchInKey){

        var object = this;

        if( Object.prototype.toString.call(needle) === '[object Object]' || 
            Object.prototype.toString.call(needle) === '[object Array]'){
            needle = JSON.stringify(needle);
        }

        return Object.keys(object).some(function(key){

            var value = object[key];

            if( Object.prototype.toString.call(value) === '[object Object]' || 
                Object.prototype.toString.call(value) === '[object Array]'){
                value = JSON.stringify(value);
            }

            if(searchInKey){
                if(value === needle || key === needle){
                return true;
                }
            }else{
                if(value === needle){
                    return true;
                }
            }
        });
    },
    writable: true,
    configurable: true,
    enumerable: false
});

Применение:

var a = {one: "first", two: "second", foo: {three: "third"}};
a.inArray("first");          //true
a.inArray("foo");            //false
a.inArray("foo", true);      //true - search by keys
a.inArray({three: "third"}); //true

var b = ["one", "two", "three", "four", {foo: 'val'}];
b.inArray("one");         //true
b.inArray('foo');         //false
b.inArray({foo: 'val'})   //true
b.inArray("{foo: 'val'}") //false

var c = "String";
c.inArray("S");        //true
c.inArray("s");        //false
c.inArray("2", true);  //true
c.inArray("20", true); //false

15

Если вы неоднократно проверяете наличие объекта в массиве, возможно, вам стоит

  1. Поддержание сортировки массива всегда путем вставки сортировки в ваш массив (поместите новые объекты в нужное место)
  2. Сделать обновление объектов как удаление + сортировка операции вставки и
  3. Используйте бинарный поиск в вашем contains(a, obj).

2
Или, если возможно, полностью прекратите использование массива и вместо этого используйте объект в качестве словаря, как предложили MattMcKnight и ninjagecko.
— Joeytwiddle

13

Решение, которое работает во всех современных браузерах:

function contains(arr, obj) {
  const stringifiedObj = JSON.stringify(obj); // Cache our object to not call `JSON.stringify` on every iteration
  return arr.some(item => JSON.stringify(item) === stringifiedObj);
}

Применение:

contains([{a: 1}, {a: 2}], {a: 1}); // true

IE6 + решение:

function contains(arr, obj) {
  var stringifiedObj = JSON.stringify(obj)
  return arr.some(function (item) {
    return JSON.stringify(item) === stringifiedObj;
  });
}

// .some polyfill, not needed for IE9+
if (!('some' in Array.prototype)) {
  Array.prototype.some = function (tester, that /*opt*/) {
    for (var i = 0, n = this.length; i < n; i++) {
      if (i in this && tester.call(that, this[i], i, this)) return true;
    } return false;
  };
}

Применение:

contains([{a: 1}, {a: 2}], {a: 1}); // true

Зачем использовать JSON.stringify?

Array.indexOfи Array.includes(а также большинство ответов здесь) сравнивают только по ссылке, а не по значению.

[{a: 1}, {a: 2}].includes({a: 1});
// false, because {a: 1} is a new object

бонус

Неоптимизированный однострочный ES6:

[{a: 1}, {a: 2}].some(item => JSON.stringify(item) === JSON.stringify({a: 1));
// true

Примечание. Сравнение объектов по значению будет работать лучше, если ключи расположены в одном и том же порядке, поэтому для безопасности можно сначала отсортировать ключи с помощью пакета, подобного следующему: https://www.npmjs.com/package/sort-keys.


Обновлена containsфункция с улучшенной оптимизацией. Спасибо, что указали на это.


Этот конкретный кусок кода может работать в IE6 (не проверял), но IE не поддерживал ES5 до IE9.
— Марк Рид,

Из соображений производительности следует избегать строковых. По крайней мере, вы должны избегать JSON.stringify «obj» в каждом цикле, потому что это дорого и замедлит ваше приложение. Для этого вы должны
— записать

1
@ Хорошее замечание. Обновил includesфункцию с вашим предложением. Я запустил jsperf с моей функцией. Это примерно в 5 раз медленнее, чем включает Лодаш. Хотя lodash не сравнивается по значению и не может найти {a: 1}в [{a: 1}]. Я не знаю, делает ли это какая-нибудь библиотека. Но мне любопытно, есть ли более эффективный и не безумно сложный способ сделать это.
— Игорь Барбашин

Позднее примечание: это не работает, скажем, contains([{ a: 1, b: 2 }], { b: 2, a: 1 })потому что строковые объекты поддерживают порядок свойств.
— Еретик Обезьяна

1
@ HereticMonkey, правда. Вот почему я добавил sort-keysпримечание внизу
— Игорь Барбашин

12

Используйте lodash это некоторая функция.

Это сжато, точно и имеет большую поддержку кроссплатформенности.

Принятый ответ даже не соответствует требованиям.

Требования: Рекомендовать наиболее краткий и эффективный способ выяснить, содержит ли массив JavaScript объект.

Принятый ответ:

$.inArray({'b': 2}, [{'a': 1}, {'b': 2}])
> -1

Моя рекомендация:

_.some([{'a': 1}, {'b': 2}], {'b': 2})
> true

Ноты:

$ .inArray отлично работает для определения, существует ли скалярное значение в массиве скаляров ...

$.inArray(2, [1,2])
> 1

... но вопрос явно требует эффективного способа определить, содержится ли объект в массиве.

Чтобы обрабатывать как скаляры, так и объекты, вы можете сделать это:

(_.isObject(item)) ? _.some(ary, item) : (_.indexOf(ary, item) > -1)

10

У ECMAScript 6 есть элегантное предложение по поиску.

Метод find выполняет функцию обратного вызова один раз для каждого элемента, присутствующего в массиве, пока не найдет элемент, в котором callback возвращает истинное значение. Если такой элемент найден, find немедленно возвращает значение этого элемента. В противном случае поиск возвращает неопределенный. обратный вызов вызывается только для индексов массива, которым присвоены значения; он не вызывается для индексов, которые были удалены или которым никогда не присваивались значения.

Вот документация MDN по этому вопросу.

Функциональность поиска работает следующим образом.

function isPrime(element, index, array) {
    var start = 2;
    while (start <= Math.sqrt(element)) {
        if (element % start++ < 1) return false;
    }
    return (element > 1);
}

console.log( [4, 6, 8, 12].find(isPrime) ); // Undefined, not found
console.log( [4, 5, 8, 12].find(isPrime) ); // 5

Вы можете использовать это в ECMAScript 5 и ниже, определив функцию .

if (!Array.prototype.find) {
  Object.defineProperty(Array.prototype, 'find', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(predicate) {
      if (this == null) {
        throw new TypeError('Array.prototype.find called on null or undefined');
      }
      if (typeof predicate !== 'function') {
        throw new TypeError('predicate must be a function');
      }
      var list = Object(this);
      var length = list.length >>> 0;
      var thisArg = arguments[1];
      var value;

      for (var i = 0; i < length; i++) {
        if (i in list) {
          value = list[i];
          if (predicate.call(thisArg, value, i, list)) {
            return value;
          }
        }
      }
      return undefined;
    }
  });
}


9

Хотя array.indexOf(x)!=-1это наиболее лаконичный способ сделать это (и поддерживается браузерами не Internet Explorer более десяти лет ...), это не O (1), а скорее O (N), что ужасно. Если ваш массив не изменится, вы можете преобразовать его в хеш-таблицу, затем выполните table[x]!==undefinedили ===undefined:

Array.prototype.toTable = function() {
    var t = {};
    this.forEach(function(x){t[x]=true});
    return t;
}

Демо-версия:

var toRemove = [2,4].toTable();
[1,2,3,4,5].filter(function(x){return toRemove[x]===undefined})

(К сожалению, хотя вы можете создать Array.prototype.contains для «замораживания» массива и сохранения хеш-таблицы в this._cache в две строки, это приведет к неверным результатам, если вы решите редактировать свой массив позже. У JavaScript недостаточно хуков для позвольте вам сохранить это состояние, в отличие от Python, например.)


9

Можно использовать Set , у которого есть метод "has ()":

function contains(arr, obj) {
      var proxy = new Set(arr);
      if (proxy.has(obj))
        return true;
      else
        return false;
    }

    var arr = ['Happy', 'New', 'Year'];
    console.log(contains(arr, 'Happy'));


5
Я думаю, что return proxy.has(obj)это намного чище, чем две строки с оператором if-else здесь
— Maciej Bukowski

function contains(arr, obj) { return new Set(arr).has(obj); }
— Гордон Бин

8

Использование:

var myArray = ['yellow', 'orange', 'red'] ;

alert(!!~myArray.indexOf('red')); //true

демонстрация

Чтобы точно знать, что tilde ~делать в этот момент, обратитесь к этому вопросу. Что делает тильда, когда она предшествует выражению? ,


5
Это было опубликовано полтора года назад, повторять не нужно.
— Shadow Wizard - это ухо для тебя

3
На самом деле, он не был опубликован. Не как ответ, а как комментарий к ответу, и даже тогда это не ясно и кратко. Спасибо за публикацию, Мина Габриэль.
— T.CK

6

ОК, вы можете просто оптимизировать свой код, чтобы получить результат!

Есть много способов сделать это, которые будут чище и лучше, но я просто хотел получить ваш паттерн и применить его JSON.stringify, просто сделайте что-то подобное в вашем случае:

function contains(a, obj) {
    for (var i = 0; i < a.length; i++) {
        if (JSON.stringify(a[i]) === JSON.stringify(obj)) {
            return true;
        }
    }
    return false;
}

Позднее примечание: это не работает, скажем, contains([{ a: 1, b: 2 }], { b: 2, a: 1 })потому что строковые объекты поддерживают порядок свойств.
— Еретик Обезьяна

5

Отнюдь не лучший, но я просто проявил творческий подход и добавил в репертуар.

Не используйте это

Object.defineProperty(Array.prototype, 'exists', {
  value: function(element, index) {

    var index = index || 0

    return index === this.length ? -1 : this[index] === element ? index : this.exists(element, ++index)
  }
})


// Outputs 1
console.log(['one', 'two'].exists('two'));

// Outputs -1
console.log(['one', 'two'].exists('three'));

console.log(['one', 'two', 'three', 'four'].exists('four'));


Что вы должны использовать, если не это?
— БРИКа

@ bryc, может быть, принятое решение или другое решение отсюда. Если вам не безразлична производительность, вы можете использовать это
— sqram

5

Удивлен, что к этому вопросу еще не добавлен последний синтаксис, добавив мои 2 цента.

Допустим, у нас есть массив Objects arrObj, и мы хотим найти в нем obj.

Array.prototype. indexOf -> (возвращает индекс или -1 ) обычно используется для поиска индекса элемента в массиве. Это также может быть использовано для поиска объекта, но работает, только если вы передаете ссылку на тот же объект.

let obj = { name: 'Sumer', age: 36 };
let arrObj = [obj, { name: 'Kishor', age: 46 }, { name: 'Rupen', age: 26 }];


console.log(arrObj.indexOf(obj));// 0
console.log(arrObj.indexOf({ name: 'Sumer', age: 36 })); //-1

console.log([1, 3, 5, 2].indexOf(2)); //3

Array.prototype. включает в себя -> (возвращает истину или ложь )

console.log(arrObj.includes(obj));  //true
console.log(arrObj.includes({ name: 'Sumer', age: 36 })); //false

console.log([1, 3, 5, 2].includes(2)); //true

Array.prototype. find -> (принимает обратный вызов, возвращает первое значение / объект, который возвращает true в CB).

console.log(arrObj.find(e => e.age > 40));  //{ name: 'Kishor', age: 46 }
console.log(arrObj.find(e => e.age > 40)); //{ name: 'Kishor', age: 46 }

console.log([1, 3, 5, 2].find(e => e > 2)); //3

Array.prototype. findIndex -> (принимает обратный вызов, возвращает индекс первого значения / объекта, который возвращает true в CB).

console.log(arrObj.findIndex(e => e.age > 40));  //1
console.log(arrObj.findIndex(e => e.age > 40)); //1

console.log([1, 3, 5, 2].findIndex(e => e > 2)); //1

Поскольку find и findIndex принимают обратный вызов, мы можем извлечь любой объект (даже если у нас нет ссылки) из массива, творчески установив истинное условие.


5

Простое решение для этого требования использует find()

Если у вас есть массив объектов, как показано ниже,

var users = [{id: "101", name: "Choose one..."},
{id: "102", name: "shilpa"},
{id: "103", name: "anita"},
{id: "104", name: "admin"},
{id: "105", name: "user"}];

Затем вы можете проверить, присутствует ли объект с вашим значением или нет

let data = users.find(object => object['id'] === '104');

если data имеет значение null, то нет администратора, иначе он вернет существующий объект, как показано ниже.

{id: "104", name: "admin"}

Затем вы можете найти индекс этого объекта в массиве и заменить объект, используя приведенный ниже код.

let indexToUpdate = users.indexOf(data);
let newObject = {id: "104", name: "customer"};
users[indexToUpdate] = newObject;//your new object
console.log(users);

вы получите значение, как показано ниже

[{id: "101", name: "Choose one..."},
{id: "102", name: "shilpa"},
{id: "103", name: "anita"},
{id: "104", name: "customer"},
{id: "105", name: "user"}];

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


5

    function countArray(originalArray) {
     
    	var compressed = [];
    	// make a copy of the input array
    	var copyArray = originalArray.slice(0);
     
    	// first loop goes over every element
    	for (var i = 0; i < originalArray.length; i++) {
     
    		var count = 0;	
    		// loop over every element in the copy and see if it's the same
    		for (var w = 0; w < copyArray.length; w++) {
    			if (originalArray[i] == copyArray[w]) {
    				// increase amount of times duplicate is found
    				count++;
    				// sets item to undefined
    				delete copyArray[w];
    			}
    		}
     
    		if (count > 0) {
    			var a = new Object();
    			a.value = originalArray[i];
    			a.count = count;
    			compressed.push(a);
    		}
    	}
     
    	return compressed;
    };
    
    // It should go something like this:
    
    var testArray = new Array("dog", "dog", "cat", "buffalo", "wolf", "cat", "tiger", "cat");
    var newArray = countArray(testArray);
    console.log(newArray);

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.