Определите, содержит ли массив значение [duplicate]

1167

Мне нужно определить, существует ли значение в массиве.

Я использую следующую функцию:

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

Вышеуказанная функция всегда возвращает false.

Значения массива и вызов функции следующие:

arrValues = ["Sam","Great", "Sample", "High"]
alert(arrValues.contains("Sam"));
  • 10
    Код работает в Safari 4.0.2. Кстати, я бы сделал === сравнение вместо просто == .
  • 1
    «Вышеприведенная функция всегда возвращает false.» Нет, это не так: функция работает должным образом - ошибка должна быть в другом месте.
Показать ещё 8 комментариев
Теги:
arrays
contains

19 ответов

956
Лучший ответ
var contains = function(needle) {
    // Per spec, the way to identify NaN is that it is not equal to itself
    var findNaN = needle !== needle;
    var indexOf;

    if(!findNaN && typeof Array.prototype.indexOf === 'function') {
        indexOf = Array.prototype.indexOf;
    } else {
        indexOf = function(needle) {
            var i = -1, index = -1;

            for(i = 0; i < this.length; i++) {
                var item = this[i];

                if((findNaN && item !== item) || item === needle) {
                    index = i;
                    break;
                }
            }

            return index;
        };
    }

    return indexOf.call(this, needle) > -1;
};

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

var myArray = [0,1,2],
    needle = 1,
    index = contains.call(myArray, needle); // true

Проверка/использование CodePen

  • 2
    Обратите внимание, что indexOf для массивов не реализован в IE, но вы можете определить его самостоятельно
  • 7
    вы должны использовать типизированное сравнение с === чтобы быть совместимым с нативной реализацией
Показать ещё 23 комментария
981

jQuery имеет функцию утилиты для этого:

$.inArray(value, array)

Возвращает индекс value в array. Возвращает -1, если array не содержит value.

См. также Как проверить, включает ли массив объект в JavaScript?

  • 161
    Не позволяйте имени inArray обмануть вас. Как упоминалось выше (но, конечно, я не читал достаточно внимательно), возвращает -1 (не ложь), если элемент не существует.
  • 5
    @ Стив Пол, что не так с именем? он делает то, что говорит: -1 = это не там, что-нибудь еще = это там
Показать ещё 7 комментариев
764

Это, как правило, метод indexOf(). Вы сказали бы:

return arrValues.indexOf('Sam') > -1
  • 0
    Мне действительно нравится, что вы можете сделать это, что по сути то же самое, что и ответ jQuery выше, но без jQuery - плюс вы можете упростить это, как указал Кеннет, хотя я не мог заставить это работать в консоли.
  • 7
    indexOf не работает в <IE9.
Показать ещё 12 комментариев
274

Array.prototype.includes()

В ES2016 есть Array.prototype.includes().

Метод includes() определяет, содержит ли массив некоторый элемент, возвращая true или false, если это необходимо.

Пример

["Sam", "Great", "Sample", "High"].includes("Sam"); // true

Поддержка

Согласно kangax и MDN, поддерживаются следующие платформы:

  • Chrome 47
  • Край 14
  • Firefox 43
  • Opera 34
  • Safari 9
  • Node 6

Поддержка может быть расширена с помощью Babel (используя babel-polyfill) или core-js. MDN также предоставляет polyfill:

if (![].includes) {
  Array.prototype.includes = function(searchElement /*, fromIndex*/ ) {
    'use strict';
    var O = Object(this);
    var len = parseInt(O.length) || 0;
    if (len === 0) {
      return false;
    }
    var n = parseInt(arguments[1]) || 0;
    var k;
    if (n >= 0) {
      k = n;
    } else {
      k = len + n;
      if (k < 0) {k = 0;}
    }
    var currentElement;
    while (k < len) {
      currentElement = O[k];
      if (searchElement === currentElement ||
         (searchElement !== searchElement && currentElement !== currentElement)) {
        return true;
      }
      k++;
    }
    return false;
  };
}
  • 3
    Я испытываю желание опубликовать этот ответ в нескольких вопросах javascript, касающихся нескольких значений переменных или массивов. Полифилл из МДН это приятно.
  • 3
    Спасибо за это! Babel polyfils это красиво :-) Я помню, 2 года назад jQuery был в любом проекте, и в настоящее время это Babel :) большая победа для сообщества JavaScript! Там есть таблица того, что доступно на ES7 уже на многих платформах, включая babel pollyfils kangax.github.io/compat-table/es2016plus
111

Почти всегда безопаснее использовать библиотеку, такую как lodash, просто из-за всех проблем с совместимостью и эффективностью кросс-браузера.

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

_.includes([1, 2, 3], 3); // returns true

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

var includes = require('lodash/collections/includes');

УВЕДОМЛЕНИЕ. В более старых версиях lodash это _.contains() а не _.includes().

  • 11
    @ threed, вам не нужно включать всю библиотеку. Частичная функциональность может быть включена с помощью require ('lodash / collection / contains').
  • 23
    К вашему сведению: с lodash 4 теперь это _.includes() вместо _.contains() .
Показать ещё 5 комментариев
46

tl; dr

function includes(k) {
  for(var i=0; i < this.length; i++){
    if( this[i] === k || ( this[i] !== this[i] && k !== k ) ){
      return true;
    }
  }
  return false;
}

Пример

function includes(k) {
  for(var i=0; i < this.length; i++){
    if( this[i] === k || ( this[i] !== this[i] && k !== k ) ){
      return true;
    }
  }
  return false;
}

function log(msg){
  $('#out').append('<div>' + msg + '</div>');  
}

var arr = [1, "2", NaN, true];
arr.includes = includes;

log('var arr = [1, "2", NaN, true];');
log('<br/>');
log('arr.includes(1): ' + arr.includes(1));
log('arr.includes(2): ' + arr.includes(2));
log('arr.includes("2"): ' + arr.includes("2"));
log('arr.includes(NaN): ' + arr.includes(NaN));
log('arr.includes(true): ' + arr.includes(true));
log('arr.includes(false): ' + arr.includes(false));
#out{
  font-family:monospace;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id=out></div>

Более длинный ответ

Я знаю, что этот вопрос не совсем о том, следует ли расширять встроенные объекты, но попытка OP и комментарии к этому ответу подчеркивают эту дискуссию. Мой комментарий от 12 февраля, 13 цитирует статью, в которой очень хорошо описываются эти дебаты, однако эта ссылка сломалась, и я не могу отредактировать исходный комментарий, потому что прошло слишком много времени, поэтому я включил его здесь.

Если вы хотите расширить встроенный объект Array с помощью метода contains, возможно, лучшим и наиболее ответственным способом сделать это будет использование этого polyfill из MDN. (См. Также этот раздел статьи MDN о прототипном наследовании, в котором объясняется, что "единственной веской причиной для расширения встроенного прототипа является обратная передача особенности новых движков JavaScript, например Array.forEach и т.д." )

if (!Array.prototype.includes) {
  Array.prototype.includes = function(searchElement /*, fromIndex*/ ) {
    'use strict';
    var O = Object(this);
    var len = parseInt(O.length) || 0;
    if (len === 0) {
      return false;
    }
    var n = parseInt(arguments[1]) || 0;
    var k;
    if (n >= 0) {
      k = n;
    } else {
      k = len + n;
      if (k < 0) {k = 0;}
    }
    var currentElement;
    while (k < len) {
      currentElement = O[k];
      if (searchElement === currentElement ||
         (searchElement !== searchElement && currentElement !== currentElement)) {
        return true;
      }
      k++;
    }
    return false;
  };
}

Не хотите строгого равенства или хотите выбрать?

function includes(k, strict) {
  strict = strict !== false; // default is true
  // strict = !!strict; // default is false
  for(var i=0; i < this.length; i++){
    if( (this[i] === k && strict) || 
        (this[i] == k && !strict) ||
        (this[i] !== this[i] && k !== k)
    ) {
      return true;
    }
  }
  return false;
}
  • 4
    Разве эта методика увеличения встроенных типов не осуждается?
  • 3
    Багги: [1,2,4].contains([].contains) верно. Также излишне медленный из-за той же ошибки. Избегайте ... в массивах.
Показать ещё 2 комментария
34

С ECMAScript6 можно использовать Set:

var myArray = ['A', 'B', 'C'];
var mySet = new Set(myArray);
var hasB = mySet.has('B'); // true
var hasZ = mySet.has('Z'); // false
18

Мой маленький вклад:

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

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

Учитывая реализацию indexOf для IE (как описано без ведома):

Array.prototype.contains = function(obj) {
    return this.indexOf(obj) > -1;
};
  • 9
    Это избыточно.
  • 10
    Возможно, но это делает ваш код чище. if (myArray.contains (obj)) легче читать и лучше формулирует намерение, чем if (myArray.indexOf (obj)> -1). Я бы окончательно реализовал оба.
Показать ещё 1 комментарий
15

Если у вас есть доступ к ECMA 5, вы можете использовать метод some.

MDN Некоторая ссылка метода

arrValues = ["Sam","Great", "Sample", "High"];

function namePresent(name){
  return name === this.toString();
}
// Note:
// namePresent requires .toString() method to coerce primitive value
// i.e. String {0: "S", 1: "a", 2: "m", length: 3, [[PrimitiveValue]]: "Sam"}
// into
// "Sam"

arrValues.some(namePresent, 'Sam');
=> true;

Если у вас есть доступ к ECMA 6, вы можете использовать метод включает.

MDN ВКЛЮЧАЕТ ссылку на метод

arrValues = ["Sam","Great", "Sample", "High"];

arrValues.includes('Sam');
=> true;
11

Вы можете использовать _. метод indexOf или если вы не хотите включать всю библиотеку Underscore.js в свое приложение, вы можете посмотрите как они это сделали и извлеките необходимый код.

    _.indexOf = function(array, item, isSorted) {
    if (array == null) return -1;
    var i = 0, l = array.length;
    if (isSorted) {
      if (typeof isSorted == 'number') {
        i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);
      } else {
        i = _.sortedIndex(array, item);
        return array[i] === item ? i : -1;
      }
    }
    if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
    for (; i < l; i++) if (array[i] === item) return i;
    return -1;
  };
9

Другой вариант - использовать Array.some (если доступно) следующим образом:

Array.prototype.contains = function(obj) {
  return this.some( function(e){ return e === obj } );
}

Анонимная функция, переданная в Array.some, вернет true тогда и только тогда, когда в массиве есть элемент, идентичный obj. Отсутствие такого элемента, функция не вернет true для любого из элементов массива, поэтому Array.some также вернет false.

6

Ничего себе, на этот вопрос есть много отличных ответов.

Я не видел того, который принимает подход reduce, поэтому я добавлю его в:

var searchForValue = 'pig';

var valueIsInArray = ['horse', 'cat', 'dog'].reduce(function(previous, current){
    return previous || searchForValue === current ? true : false;
}, false);

console.log('The value "' + searchForValue + '" is in the array: ' + valueIsInArray);

Здесь скрипка в действии.

  • 0
    Я действительно думал о том, чтобы пойти по этому маршруту, но он все равно должен пересечь весь массив, даже когда результат найден.
  • 1
    @ Cgatian это хороший момент. Это определенно нужно учитывать при выборе метода для использования. Вы могли бы потенциально обернуть инструкцию Reduce в блок try catch и выдать исключение, как только вы нашли значение, но если вы сделаете это, я думаю, вы потеряете некоторую простоту, которую дает вам функциональный подход.
4

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

Ссылка: Array.prototype.map()

Этот метод может хорошо работать как для простых массивов, так и для массивов объектов, где вам нужно увидеть, существует ли ключ/значение в массиве объектов.

function inArray(myArray,myValue){
    var inArray = false;
    myArray.map(function(key){
        if (key === myValue){
            inArray=true;
        }
    });
    return inArray;
};

var anArray = [2,4,6,8]
console.log(inArray(anArray, 8)); // returns true
console.log(inArray(anArray, 1)); // returns false

function inArrayOfObjects(myArray,myValue,objElement){
    var inArray = false;
    myArray.map(function(arrayObj){
        if (arrayObj[objElement] === myValue) {
            inArray=true;
        }
    });
    return inArray;
};

var objArray = [{id:4,value:'foo'},{id:5,value:'bar'}]
console.log(inArrayOfObjects(objArray, 4, 'id')); // returns true
console.log(inArrayOfObjects(objArray, 'bar', 'value')); // returns true
console.log(inArrayOfObjects(objArray, 1, 'id')); // returns false
4

Ответ предоставлен не для меня, но он дал мне идею:

Array.prototype.contains = function(obj)
    {
        return (this.join(',')).indexOf(obj) > -1;
    }

Это не идеально, потому что элементы, которые являются одинаковыми вне группировок, могут привести к совпадению. Например, мой пример

var c=[];
var d=[];
function a()
{
    var e = '1';
    var f = '2';
    c[0] = ['1','1'];
    c[1] = ['2','2'];
    c[2] = ['3','3'];
    d[0] = [document.getElementById('g').value,document.getElementById('h').value];

    document.getElementById('i').value = c.join(',');
    document.getElementById('j').value = d.join(',');
    document.getElementById('b').value = c.contains(d);
}

Когда я вызываю эту функцию с полями "g" и "h", содержащими 1 и 2 соответственно, он все равно находит это, потому что результирующая строка из объединения: 1,1,2,2,3,3

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

  • 1
    Это решение кажется очень хрупким и подверженным ошибкам во всех случаях, кроме самых узких. Представьте себе, например, использование этого массива: var arr = ["Smith, Reed", "Jackson, Frank"]; arr.contains(searchTerm); Представьте, что какой-то пользователь случайно набрал "Reed,Jackson" вместо "Reed, Jackson" в каком-то текстовом поле, которое просматривало этот массив. Этот алгоритм будет возвращать ложное срабатывание, и пользователь будет думать, что Reed, Jackson действительно существует, когда его нет. Случаи, подобные этому, делают этот алгоритм более склонным к ошибкам.
2
function setFound(){   
 var l = arr.length, textBox1 = document.getElementById("text1");
    for(var i=0; i<l;i++)
    {
     if(arr[i]==searchele){
      textBox1 .value = "Found";
      return;
     }
    }
    textBox1 .value = "Not Found";
return;
}

Эта программа проверяет, найден ли данный элемент или нет. Я бы text1 представляет собой идентификатор текстового поля, а поисковый запрос представляет элемент, который должен быть поиск (получил пользователь fron); если вам нужен индекс, используйте значение i

  • 4
    Пожалуйста, дайте объяснение вашего кода. Код только ответы не оценены
  • 1
    Эта программа проверяет, найден ли данный элемент или нет. Идентификатор text1 представляет идентификатор текстового поля, а Searchele представляет элемент для поиска (получил от пользователя); если вы хотите индекс, используйте значение i.
Показать ещё 1 комментарий
1

Простейшим решением для функции contains будет функция, которая выглядит так:

var contains = function (haystack, needle) {
    return !!~haystack.indexOf(needle);
}

В идеале вы бы не сделали это автономной функцией, а частью вспомогательной библиотеки:

var helper = {};

helper.array = {
    contains : function (haystack, needle) {
        return !!~haystack.indexOf(needle);
    }, 
    ...
};

Теперь, если вы оказались одним из тех неудачливых людей, которые все еще нуждаются в поддержке IE < 9 и, следовательно, не могут полагаться на indexOf, вы можете использовать этот polyfill, который я получил из MDN:

if (!Array.prototype.indexOf) {
  Array.prototype.indexOf = function(searchElement, fromIndex) {
    var k;
    if (this == null) {
      throw new TypeError('"this" is null or not defined');
    }
    var o = Object(this);
    var len = o.length >>> 0;
    if (len === 0) {
      return -1;
    }
    var n = +fromIndex || 0;

    if (Math.abs(n) === Infinity) {
      n = 0;
    }
    if (n >= len) {
      return -1;
    }
    k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
    while (k < len) {
      if (k in o && o[k] === searchElement) {
        return k;
      }
      k++;
    }
    return -1;
  };
}
-1

Я очень рекомендую это -

if(/Element/g.test(Array)){---}
-5

Я предпочитаю простоту:

var days = [1, 2, 3, 4, 5];
if ( 2 in days ) {console.log('weekday');}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню