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

3274

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

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

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

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

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

  • 42
    только что проверил: ваш путь на самом деле самый быстрый для всех браузеров: jsperf.com/find-element-in-obj-vs-array/2 (кроме предварительного сохранения a.length в переменной) при использовании indexOf (как в $ .inArray) намного медленнее
  • 14
    многие ответили, что Array # indexOf - ваш лучший выбор здесь. Но если вы хотите что-то, что может быть правильно приведено к Boolean, используйте это: ~[1,2,3].indexOf(4) вернет 0, что оценивается как ложное, тогда как ~[1,2,3].indexOf(3) вернет -3, что будет оцениваться как истина.
Показать ещё 4 комментария
Теги:
arrays
browser
javascript-objects

44 ответа

4047
Лучший ответ

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

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

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

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

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

Некоторые другие структуры предлагают аналогичные методы:

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

  • 41
    MooTools также имеет Array.contains, который возвращает логическое значение, которое здесь звучит как настоящий вопрос.
  • 19
    Прототип также имеет Array.include которое возвращает логическое значение
Показать ещё 18 комментариев
373

Обновление. Поскольку @orip упоминает в комментариях, связанный бенчмарк был выполнен в 2008 году, поэтому результаты могут не иметь отношения к современным браузерам. Однако вам, вероятно, понадобится это, чтобы поддерживать несовременные браузеры в любом случае, и, вероятно, они не обновлялись с тех пор. Всегда проверяйте себя.

Как говорили другие, итерация через массив, вероятно, является лучшим способом, но доказано, что уменьшающийся цикл 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
  • 23
    Но будьте осторожны: stackoverflow.com/questions/237104/javascript-array-containsobj/…
  • 0
    Это прекрасно работает с Titanium 1.7.2.
Показать ещё 12 комментариев
169

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

  • 0
    на самом деле, есть пример реализации расширения indexOf для браузеров, которые не поддерживают его, на странице developer.mozilla.org, на которую вы ссылаетесь.
  • 0
    на самом деле, если вы добавите indexof к прототипу Array для браузеров, которые его не поддерживают (например, IE7), они также попытаются перебрать эту функцию при циклическом просмотре элементов в массиве. противно.
Показать ещё 2 комментария
145

В 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, который использует Strict Equality Comparison, includes сравнивается с использованием SameValueZero. Это означает, что вы можете определить, содержит ли массив NaN:

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

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

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

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

  • 3
    Не поддерживается для IE и Microsfot Edge (2015) ( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… )
  • 1
    Также имеет значение таблица совместимости ES7 (похоже, что Chrome поддерживает ее сейчас)
Показать ещё 2 комментария
105

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

function(a, b) {
    return a.indexOf(b) != -1
}
  • 0
    Он возвращает true, если «b» находится в массиве «a» ... Я не знаю, как еще это объяснить ...
  • 4
    Эту часть я не понимаю "!! ~". И я думаю, что это не будет работать в IE8, потому что IE8 не поддерживает indexOf () для объекта Array.
Показать ещё 5 комментариев
71

Вот совместимая с 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;
        };
}
  • 0
    Это выглядит великолепно, но немного сбито с толку: * Разве тесты в строках 1 и 3 не эквивалентны? * Не лучше ли протестировать прототип и добавить функцию в Array.prototype, если это необходимо?
  • 10
    Они не эквивалентны. [].indexOf является сокращением для Array.prototype.indexOf . Мы, параноидальные защитники Javascript, избегаем расширения собственных прототипов любой ценой.
Показать ещё 2 комментария
61

Верхние ответы предполагают примитивные типы, но если вы хотите узнать, содержит ли массив объект с некоторой чертой, 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
    @jamess Это может хорошо поддерживаться, но помните, что Arrow functions в этом примере не так хорошо поддерживаются. Для получения дополнительной информации см. Здесь: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
52

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

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

// Usage
if(isInArray(my_array, "my_value"))
{
    //...
}
  • 25
    x ? true : false обычно избыточен. Это здесь.
  • 0
    @minitech Почему вы говорите, что это избыточно?
Показать ещё 3 комментария
40

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

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

  • 22
    Я не согласен. По этой причине циклы for-in не должны использоваться для массивов. Использование циклов for-in прекратится при использовании одной из популярных библиотек js
  • 0
    Будет ли это считаться исправлением обезьяны? LOL Некоторые люди, как это.
27

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

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

  • 0
    Хотя это, очевидно, полезно для многих, было бы лучше, если бы был добавлен фрагмент кода.
24

Однострочник:

function contains(arr, x) {
    return arr.filter(function(elem) { return elem == x }).length > 0;
}
  • 5
    array.filter(e=>e==x).length > 0 эквивалентна array.some(e=>e==x) но some более эффективны
22

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

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

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

a.contains('foo'); // true
a.contains('fox'); // false
19
function contains(a, obj) {
    return a.some(function(element){return element == obj;})
}

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

  • 0
    при использовании es6 его можно сократить, поскольку он contains = (a, obj) => a.some((element) => element === obj))
  • 0
    Даже в IE9 есть поддержка Array.prototype.some (), начиная с ECMAScript 5 .
14

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

2015

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

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

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

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

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

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

Двунаправленный индексOf/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 тыс. записей.

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

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

Примечание. Как вы можете видеть, я слегка изменил функцию 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');

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

И вот вариант 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

12

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

/*
 * @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
  • 0
    Я просто оставлю это здесь JS-inArray
12
function inArray(elem,array)
{
    var len = array.length;
    for(var i = 0 ; i < len;i++)
    {
        if(array[i] == elem){return i;}
    }
    return -1;
} 

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

12

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

  • Сохранение массива, отсортированного во все времена, делая insertion sort в вашем массиве (помещаем новые объекты в нужное место)
  • Сделать обновления объектов в качестве операции удаления + сортировки вставки и
  • Используйте бинарный поиск в вашем contains(a, obj).
  • 2
    Или, если возможно, полностью прекратите использование массива и вместо этого используйте объект в качестве словаря, как предложили MattMcKnight и ninjagecko.
10

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

9

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

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 функцию с оптимизацией перфорации. Спасибо, что указали на это.

  • 0
    Этот конкретный кусок кода может работать в IE6 (не проверял), но IE не поддерживал ES5 до IE9.
  • 0
    Из соображений производительности следует избегать строковых. По крайней мере, вы должны избегать JSON.stringify «obj» в каждом цикле, потому что это дорого и замедлит ваше приложение. Поэтому вы должны записать его перед циклом for во временной переменной
Показать ещё 1 комментарий
9

Используйте lodash some.

Это краткий, точный и удобный кросс-платформенный интерфейс.

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

Требования: рекомендуйте наиболее краткий и эффективный способ узнать, содержит ли массив 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)
8

В то время как array.indexOf(x)!=-1 является наиболее кратким способом сделать это (и был поддержан браузерами не интернет-браузеров более десятилетия...), это не 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 в двух строках, это приведет к неправильным результатам, если вы захотите позже отредактировать свой массив. недостаточно крючков, чтобы вы могли сохранить это состояние, в отличие от Python, например.)

7

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

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

Ниже приведена документация 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;
    }
  });
}
6

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

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

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

Демо

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

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

Здесь Прототип делает это:

/**
 *  Array#indexOf(item[, offset = 0]) -> Number
 *  - item (?): A value that may or may not be in the array.
 *  - offset (Number): The number of initial items to skip before beginning the
 *      search.
 *
 *  Returns the position of the first occurrence of `item` within the array &mdash; or
 *  `-1` if `item` doesn't exist in the array.
**/
function indexOf(item, i) {
  i || (i = 0);
  var length = this.length;
  if (i < 0) i = length + i;
  for (; i < length; i++)
    if (this[i] === item) return i;
  return -1;
}

Также см. здесь для их подключения.

3

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

Есть много способов сделать это, которые будут чище и лучше, но я просто хотел получить ваш шаблон и применить к нему, используя 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;
}
3

Вы также можете использовать этот трюк:

var arrayContains = function(object) {
  return (serverList.filter(function(currentObject) {
    if (currentObject === object) {
      return currentObject
    }
    else {
      return false;
    }
  }).length > 0) ? true : false
}
  • 0
    это кажется запутанным. 'object' - плохое имя, 'item' может быть лучше. логика функции фильтра должна просто возвращать currentObject === item; и троичный оператор не нужен ..
3

Можно использовать 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'));
  • 2
    Я думаю, что return proxy.has(obj) намного чище, чем две строки с оператором if-else здесь
3

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

Array.prototype.contains = function(x){
  var retVal = -1;

  // x is a primitive type
  if(["string","number"].indexOf(typeof x)>=0 ){ retVal = this.indexOf(x);}

  // x is a function
  else if(typeof x =="function") for(var ix in this){
    if((this[ix]+"")==(x+"")) retVal = ix;
  }

  //x is an object...
  else {
    var sx=JSON.stringify(x);
    for(var ix in this){
      if(typeof this[ix] =="object" && JSON.stringify(this[ix])==sx) retVal = ix;
    }
  }

  //Return False if -1 else number if numeric otherwise string
  return (retVal === -1)?false : ( isNaN(+retVal) ? retVal : +retVal);
}

Я знаю, что это не лучший способ пойти, но поскольку нет никакого естественного способного для взаимодействия между объектами, я полагаю, что это так близко, что вы можете сравнить два объекта в массиве. Кроме того, расширение объекта Array может быть неразумным, но иногда это нормально (если вы знаете об этом и компромисс).

2
  • Либо используйте Array.indexOf(Object).
  • С ECMA 7 можно использовать массив Array.includes(Object).
  • С ECMA 6 вы можете использовать Array.find(FunctionName), где FunctionName является пользователем определенную функцию для поиска объекта в массиве.

    Надеюсь, что это поможет!

2

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

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

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'));
  • 0
    Что вы должны использовать, если не это?
  • 0
    @ bryc, может быть, принятое решение или другое решение отсюда. Если вы не очень заботитесь о производительности, чем вы можете использовать это
2

Как уже упоминалось, вы можете использовать Array.indexOf, но он недоступен во всех браузерах. Здесь код https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf, чтобы он работал в старых браузерах.

indexOf - последнее дополнение к стандарту ECMA-262; как таковой он может не присутствовать во всех браузерах. Вы можете обойти это, вставив следующий код в начале ваших сценариев, позволяющий использовать indexOf в реализациях, которые его не поддерживают. Эта алгоритм точно такой, который указан в ECMA-262, 5th edition, предполагая Object, TypeError, Number, Math.floor, Math.abs и Math.max имеют свое первоначальное значение.

if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
        "use strict";
        if (this == null) {
            throw new TypeError();
        }
        var t = Object(this);
        var len = t.length >>> 0;
        if (len === 0) {
            return -1;
        }
        var n = 0;
        if (arguments.length > 1) {
            n = Number(arguments[1]);
            if (n != n) { // shortcut for verifying if it NaN
                n = 0;
            } else if (n != 0 && n != Infinity && n != -Infinity) {
                n = (n > 0 || -1) * Math.floor(Math.abs(n));
            }
        }
        if (n >= len) {
            return -1;
        }
        var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
        for (; k < len; k++) {
            if (k in t && t[k] === searchElement) {
                return k;
            }
        }
        return -1;
    }
}
1

Я рекомендовал использовать библиотеку underscore, потому что она возвращает значение и поддерживается для всех браузеров.

underscorejs

 var findValue = _.find(array, function(item) {
    return item.id == obj.id;
 });
1

Если вы работаете с ES6, вы можете использовать набор:

function arrayHas( array, element ) {
    const s = new Set(array);
    return s.has(element)
}

Это должно быть более эффективным, чем любой другой метод

  • 1
    Как это более производительно? По крайней мере, вы должны построить множество, которое является O (n) (вы должны перебрать массив). Просто выполнять линейный поиск (как indexOf делает indexOf ) - тоже O (n) , но только в худшем случае. Средняя сложность случая больше похожа на n / 2 , поскольку, если массив содержит элемент, вы, скорее всего, остановитесь где-то посередине. Следовательно, этот метод в среднем медленнее, чем Array#includes и Array#indexOf .
1

Он имеет один параметр: номера массивов объектов. Каждый объект в массиве имеет два целочисленных свойства, обозначаемых x и y. Функция должна возвращать подсчет всех таких объектов в массиве, которые удовлетворяют numbers.x == numbers.y

var numbers = [ { x: 1, y: 1 },
                 { x: 2, y: 3 },
                 { x: 3, y: 3 },
                 { x: 3, y: 4 },
                 { x: 4, y: 5 } ];
    count = 0; 
var n = numbers.length;
for (var i =0;i<n;i++)
{
  if(numbers[i].x==numbers[i].y)
  {count+=1;}
}

alert(count);
  • 0
    Как бы вы сравнили значение x со следующим значением x элементов? Это не работает: for (var i = 0; i < n; i++) { if (numbers[i].x == (numbers[i] + 1).x) { count += 1; } }
1

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

function set(arr) {
    var res = [];
    for (var i = 0; i < arr.length; i++) {
        if (res.indexOf(arr[i]) === -1) {
            res.push(arr[i]);
        }
    }
    return res;
}
1

Или это решение:

Array.prototype.includes = function (object) {
  return !!+~this.indexOf(object);
};
1

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

Но скажем, что у вас нет ссылки на объект, как вы найдете правильный объект в массиве? Вам придется идти линейно и глубоко по сравнению с каждым объектом. Представьте, если список слишком велик, а объекты в нем очень большие, содержащие большие фрагменты текста. Производительность резко падает с количеством и размером элементов в массиве.

Вы можете стягивать объекты и помещать их в собственную хеш-таблицу, но тогда у вас будет избыточность данных, запоминающая эти ключи, потому что JavaScript сохраняет их для "для я в obj", и вы хотите только проверить, существует ли этот объект или нет, то есть у вас есть ключ.

Я некоторое время думал об этом, создав механизм проверки JSON Schema, и я разработал простую оболочку для собственной хеш-таблицы, аналогичную единственной реализации хэш-таблицы, с некоторыми исключениями оптимизации, которые я оставил в собственной хеш-таблице с. Это нужно только для бенчмаркинга производительности... Все подробности и код можно найти в моем блоге: http://stamat.wordpress.com/javascript-quickly-find-very-large-objects-in-a-large-array/ Я скоро опубликую результаты тестов.

Полное решение работает следующим образом:

var a = {'a':1,
 'b':{'c':[1,2,[3,45],4,5],
 'd':{'q':1, 'b':{'q':1, 'b':8},'c':4},
 'u':'lol'},
 'e':2};

 var b = {'a':1, 
 'b':{'c':[2,3,[1]],
 'd':{'q':3,'b':{'b':3}}},
 'e':2};

 var c = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.";

 var hc = new HashCache([{a:3, b:2, c:5}, {a:15, b:2, c:'foo'}]); //init

 hc.put({a:1, b:1});
 hc.put({b:1, a:1});
 hc.put(true);
 hc.put('true');
 hc.put(a);
 hc.put(c);
 hc.put(d);
 console.log(hc.exists('true'));
 console.log(hc.exists(a));
 console.log(hc.exists(c));
 console.log(hc.exists({b:1, a:1}));
 hc.remove(a);
 console.log(hc.exists(c));
1

Аналогичная вещь: находит первый элемент с помощью "поиска лямбда":

Array.prototype.find = function(search_lambda) {
  return this[this.map(search_lambda).indexOf(true)];
};

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

[1,3,4,5,8,3,5].find(function(item) { return item % 2 == 0 })
=> 4

То же самое в coffeescript:

Array.prototype.find = (search_lambda) -> @[@map(search_lambda).indexOf(true)]
  • 0
    Это, безусловно, гораздо более гибкий, чем многие другие подходы. Если кому-то неудобно с прототипом, можно рассмотреть что-то вроде var positionIf = function (предикат, последовательность) {return sequence.map (предикат) .indexOf (true);};
  • 2
    Более эффективным способом реализации этого метода было бы использование цикла и прекращение применения search_lambda только что-то найдено.
0
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 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);
0

В дополнение к тому, что говорили другие, если у вас нет ссылки на объект, который вы хотите найти в массиве, вы можете сделать что-то вроде этого.

let array = [1, 2, 3, 4, {"key": "value"}];

array.some((element) => JSON.stringify(element) === JSON.stringify({"key": "value"})) // true

array.some((element) => JSON.stringify(element) === JSON.stringify({})) // true

Array.some возвращает true, если какой-либо элемент соответствует данному условию и возвращает false, если ни один из элементов не соответствует данному условию.

0

Простое решение: ES6 Особенности " включает " метод

let arr = [1, 2, 3, 2, 3, 2, 3, 4];

  arr.includes(2) // true

  arr.includes(93) // false
0

Использование idnexOf() это хорошее решение, но вы должны скрыть встроенную функцию indexOf(), которая возвращает -1 с помощью оператора ~:

function include(arr,obj) { 
    return !!(~arr.indexOf(obj)); 
} 
-4

Просто еще один вариант

// usage: if ( ['a','b','c','d'].contains('b') ) { ... }
Array.prototype.contains = function(value){
    for (var key in this)
        if (this[key] === value) return true;
    return false;
}

Будьте осторожны, потому что перегрузка объектов массива javascript пользовательскими методами может нарушить поведение других javascript и вызвать непредвиденное поведение.

  • 1
    Но будьте осторожны: stackoverflow.com/questions/237104/javascript-array-containsobj/…
  • 22
    Пожалуйста , не использовать for in цикле перебрать массив - for in петлях должны использоваться строго только для объектов.
-7

Дословно:

(используя Firefox v3.6, с предостережениями for-in, как ранее отмечалось (ОДНАКО, что использование ниже может означать for-in для этой цели! То есть перечисление элементов массива, которые ACTUALLY существуют через индекс свойств (HOWEVER, в частности, свойство array length НЕ перечисляется в списке свойств for-in!).).)

(Перетащите следующий полный URI для тестирования браузера в режиме немедленного режима.)

JavaScript:

  function ObjInRA(ra){var has=false; for(i in ra){has=true; break;} return has;}

  function check(ra){
      return ['There is ',ObjInRA(ra)?'an':'NO',' object in [',ra,'].'].join('')
  }
  alert([
            check([{}]), check([]), check([,2,3]),
            check(['']), '\t (a null string)', check([,,,])
        ].join('\n'));

который отображает:

There is an object in [[object Object]].
There is NO object in [].
There is an object in [,2,3].
There is an object in [].
     (a null string)
There is NO object in [,,].

Морщины: если вы ищете "конкретный" объект, подумайте:

JavaScript: alert({}!={}); alert({}!=={});

И таким образом:

JavaScript:

 obj = {prop:"value"}; 
 ra1 = [obj]; 
 ra2 = [{prop:"value"}];
 alert(ra1[0] == obj); 
 alert(ra2[0] == obj);

Часто ra2 считается "содержать" obj как литеральный объект {prop:"value"}.

Очень грубая, рудиментарная, наивная (как в коде нуждается повышение квалификации):

JavaScript:

  obj={prop:"value"};   ra2=[{prop:"value"}];
  alert(
    ra2 . toSource() . indexOf( obj.toSource().match(/^.(.*).$/)[1] ) != -1 ?
      'found' :
      'missing' );

См. ссылку: Поиск объектов в массивах JavaScript.

Ещё вопросы

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