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

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

Это единственный известный мне способ:

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

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

Это очень тесно связано с вопросом Stack Overflow Best way to find an item in a JavaScript Array?, который касается поиска объектов в массиве с помощью indexOf.

Комментарии к вопросу (8)
Решение

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

> ['joe', 'jane', 'mary'].includes('jane');
true 

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

jQuery предлагает $.inArray, который функционально эквивалентен Array#indexOf.

underscore.js, библиотека утилит JavaScript, предлагает _.contains(list, value), псевдоним _.include(list, value), оба из которых используют indexOf внутренне, если передается массив JavaScript.

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

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

Комментарии (24)

Обновление от 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
Комментарии (16)

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 (например, этот).

Комментарии (4)

В ECMAScript 7 вводит массива.прототип.включает.

Он может быть использован такой:

[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, который использует строгая сравнения, включает сравнивает используя SameValueZero алгоритм равенства. Это означает, что вы можете обнаружить, если массив включает в себя Нана:

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

Также в отличие от помощи indexOf, включает в себя не пропустите недостающие показатели:

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

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

Комментарии (4)

B - это значение, и A - это массив. Он возвращает true или false:

function(a, b) {
    return a.indexOf(b) != -1
}
Комментарии (6)

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

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 (items.some(item => item.a === '3')) {
  // do something
}

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

Комментарии (5)

Здесь'ы код JavaScript совместимый 1.6 реализация массива.метод 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;
        };
}
Комментарии (4)

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

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

// Usage
if(isInArray(my_array, "my_value"))
{
    //...
}
Комментарии (5)

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

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

Комментарии (2)

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

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

Комментарии (1)

Один-лайнер:

function contains(arr, x) {
    return arr.filter(function(elem) { return elem == x }).length > 0;
}
Комментарии (1)

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

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

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

a.contains('foo'); // true
a.contains('fox'); // false
Комментарии (0)
function contains(a, obj) {
    return a.some(function(element){return element == obj;})
}

Array.prototype.some() был добавлен в ECMA-262 стандарт в 5-е издание

Комментарии (2)

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

2015

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

Это'ы давно, что я думал о пути, чтобы заменить медленный метод indexOf/lastIndexOf функции.

Более производительный способ уже найден, глядя на лучшие ответы. Из тех, кого я выбрал содержит функции сообщение от @Дамир zekic в который должен быть самым быстрым. Но в нем также говорится, что показатели с 2008 года и так устарели.

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

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

Когда вы знаете, вы просто толкнул массив со значением, используя 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

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

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

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

Примечание: как вы видите, я немного изменил содержит чтобы отразить метод indexOf &ампер; выход lastIndexOf (так в основном истинный с индекс и 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');

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

И вот это пока вариант:

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

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

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

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

http://jsperf.com/bidirectionalindexof/2

Комментарии (0)
function inArray(elem,array)
{
    var len = array.length;
    for(var i = 0 ; i < len;i++)
    {
        if(array[i] == elem){return i;}
    }
    return -1;
} 

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

Комментарии (0)

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

Комментарии (0)

Если вы регулярно проверяете на существование объекта в массив, вам стоит заглянуть в

  1. Держать массив отсортированный во все времена, делая сортировка вставкой в своем массива (поставили новые объекты на нужное место)
  2. Сделать обновление объектов как удалить+отсортированный операции вставки и
  3. Использовать двоичный поиск поиска содержит(а, объект)`.
Комментарии (1)

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

/*
 * @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
Комментарии (1)

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

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

Решение ИЕ6+:

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.преобразовать в строки`?

Массива.помощи indexOf и `массива.включает в себя (как и большинство ответов здесь) сравнивать только по ссылке и не по значению.

[{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


Обновленная функция содержит с перф оптимизации. Спасибо itinance для указания.

Комментарии (5)

Использовать 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)
Комментарии (0)