Як перевірити, чи містить масив значення JavaScript?


3994

Який найбільш стислий та ефективний спосіб з’ясувати, чи містить масив 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, ~це побітовий НЕ оператор , див. ES5 11.4.8. Справа в тому, що оскільки двійкове представлення -1складається лише з 1, це доповнення 0, яке оцінюється як помилкове. Доповнення будь-якого іншого числа буде не нульовим, отже, істинним. Отже, ~працює просто чудово і часто використовується спільно з indexOf.
mknecht

5
Назва вводить в оману. Де знаходиться [[1,2],[3,4]].includes([3,4])?
mplungjan

Відповіді:


4374

Сучасні браузери 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 і буде оцінений як falsy
плюс -

241
inArray- жахлива назва функції, яка повертає індекс елемента, а -1якщо він не існує. Я очікував би повернення булева.
Тім

433

Оновлення від 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 роки тому, жахливо застаріла.
Оріп

2
@Damir - я згоден. Можливо, змініть зразок, щоб він використовував indexOf, якщо він доступний, просто щоб люди копіювали цей код наосліп, отримають найкращі показники.
orip

1
@cbmeeks так, обов'язково потрібен догляд. Це, мабуть, був такий випадок, for (o in array)якого не слід робити під час циклічного перегляду масиву ...
Дамір Зекич

1
Найкращий спосіб зробити це - перевірити, чи [1, 2, 3] .indexOf (1)> -1
Devin G Rhode

206

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


чи застосовна перевірка на об'єкт. я не думаю, що це спрацює у випадку об'єкта
Хімеш Адешара

168

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/… )
Adriano Resende

1
Також актуально таблицю сумісності ES7 (схоже, що це підтримує хром)
styfle

чи застосовна перевірка на об'єкт. я не думаю, що це спрацює у випадку об'єкта
Хімеш Адешара

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
}

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


1
Станом на сьогодні, вересень 2018 року, Array.prototype.some () повністю підтримується: таблиця підтримки
caniuse.com

1
Робота в Node> = 8.10 для AWS Node.js Lambda, тому це чудово. Дуже чисте і просте рішення! 👍🏻
Йорданія

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

Як звичайний метод масиву (до 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

Це повертається істиною, якщо "b" знаходиться в масиві "a" ... я не знаю, як ще пояснити це ...
william malo

4
Цю частину я не розумію "!! ~". І я думаю, що це не буде працювати в IE8, оскільки IE8 не підтримує indexOf () на об’єкті Array.
svlada

62
"~" - оператор, що поверхи, обертання та віднімання 1 від числа. indexOf повертає -1, якщо він не працює, тому "~" перетворюється -1 у "0". використовуючи "!!" перетворює числа в болеани (!! 0 === false)
william malo

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

2
Я б назвав відсутність знань про вплив булевих операторів непрофесійними. Але я погоджуюсь із значенням читабельного коду, я б, безумовно, зафіксував це у чітко позначеній функції. Саме це і роблять більшість основних програм JS.
okdewit

79

Ось сумісна реалізація JavaScript 1.6Array.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 уникають розширення нативних прототипів за будь-яку ціну.
Már Örlygsson

1
Чи не [].indexOfстворює новий масив, а потім отримує доступ indexOf, в той час як Array.prototype.indexOfпросто звертається до прототипу безпосередньо?
alex

3
@alex так [].indexOf === Array.prototype.indexOf(спробуйте це у FireBug), але навпаки [].indexOf !== Array.indexOf.
Már Örlygsson

57

Використання:

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

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

25
x ? true : falseзазвичай є зайвим. Це тут.
Ри-

@minitech Чому ти вважаєш, що це зайве?
Матіас Канепа

8
array.indexOf(search) >= 0вже булевий. Просто return array.indexOf(search) >= 0.
Ри-

@minitech добре дякую! Насправді я не знав, що таку конструкцію можна повернути. TIL щось нове.
Matías Cánepa

Буквально будь-яку конструкцію в JavaScript можна повернути
BT

49

Розширення Arrayоб’єкта JavaScript - це дуже погана ідея, оскільки ви вводите нові властивості (ваші власні методи) у for-inпетлі, які можуть порушити існуючі сценарії. Кілька років тому автори прототипу бібліотеки довелося переробити свою бібліотечну реалізацію, щоб видалити саме цю річ.

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


22
Я не погоджуюсь. Цифри for-in не повинні використовуватися для масивів саме з цієї причини. Використання циклів for-in порушиться при використанні однієї з популярних js-бібліотек
Tomas

Чи вважатиметься це виправленням мавпи? 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


Хоча це, очевидно, корисно для багатьох, було б краще, якби був доданий фрагмент коду.
Пиріг «Ой» Pah

28

Я використовую наступне:

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

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

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

24
function contains(a, obj) {
    return a.some(function(element){return element == obj;})
}

Array.prototype.some () було додано до стандарту ECMA-262 у 5-му випуску


якщо використовувати es6, ніж його, можна скоротитиcontains = (a, obj) => a.some((element) => element === obj))
diEcho

Навіть IE9 має підтримку Array.prototype.some () станом на ECMAScript 5 .
Suncat2000

19

Сподіваємось, швидший двосторонній indexOf/ lastIndexOfальтернативний варіант

2015 рік

Незважаючи на те, що новий метод включає дуже приємно, підтримка в даний час в основному дорівнює нулю.

Давно я думав над способом замінити повільні функції indexOf / lastIndexOf.

Виконаний шлях уже знайдено, дивлячись на відповіді вгорі. З тих, кого я вибравcontains функцію, яку опублікував @Damir Zekic, яка повинна бути найшвидшою. Але також зазначено, що орієнтири є з 2008 року і тому застаріли.

Я також віддаю перевагу whileнад for, але з не певної причини я закінчив писати функцію циклом for. Це також можна зробити з awhile -- .

Мені було цікаво, чи ітерація була набагато повільнішою, якщо я перевіряю обидві сторони масиву, роблячи це. Мабуть, ні, і тому ця функція приблизно в два рази швидша, ніж голосові вгорі. Очевидно, він також швидший, ніж рідний. Це в реальному світі, коли ви ніколи не знаєте, чи є значення, яке ви шукаєте, на початку або в кінці масиву.

Коли ви знаєте, що ви просто натиснули масив зі значенням, використання 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 я виконую тести на MacOs HighSierra 10.13.6 на Chrome v78.0.0, Safari v13.0.4 та Firefox v71.0.0 для 15 обраних рішень. Висновки

  • рішення на основі JSON, Setі дивно find(K, N, O) найповільніші у всіх браузерах
  • es6 includes(F) швидкий лише на хромі
  • розчини на основі for(C, D) таindexOf (G, H) досить швидкі для всіх браузерів на малих та великих масивах, тому, ймовірно, вони є найкращим вибором для ефективного рішення
  • рішення, де зменшення індексу під час циклу, (B) повільніше, ймовірно, тому, що працює спосіб кешу процесора .
  • Я також запускаю тест на великий масив, коли шуканий елемент знаходився на позиції 66% довжини масиву, а рішення на основі for(C, D, E) дають подібні результати (~ 630 ops / sec - але E на сафарі та 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
Або, якщо можливо, перестаньте використовувати Array повністю і замість цього використовуйте Object як словник, як запропонували 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функцію за допомогою оптимізації perf. Дякуємо itinance за його вказівку.


Цей конкретний фрагмент коду може працювати в IE6 (не перевірений), але IE не підтримував ES5 до IE9.
Марк Рід

З міркувань продуктивності слід уникати різкості. Принаймні, вам слід уникати JSON.stringify "obj" на кожному циклі, оскільки він дорогий і сповільнить вашу програму. Для цього вам слід зафіксувати його перед циклом for-for у тимчасовій змінній
itinance

1
@itinance хороший момент. Оновіть 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 виконує функцію зворотного виклику один раз для кожного елемента, присутнього в масиві, поки він не знайде той, де зворотний виклик повертає справжнє значення. Якщо такий елемент знайдений, пошук негайно повертає значення цього елемента. В іншому випадку знайдіть прибутки невизначеними. зворотний виклик викликається лише для індексів масиву, яким призначені значення; він не викликається для індексів, які були видалені або яким ніколи не було призначено значень.

Ось документація 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, щоб "заморозити" масив і зберегти хештель у цьому. нехай ви збережете цей стан, на відміну від 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 тут
Мацей Буковський,

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 is Ear for You

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

@bryc, можливо, прийняте рішення, або інше рішення звідси. Якщо ви не дуже піклуєтесь про ефективність, то можете скористатися цим
sqram

5

Здивовано, що до цього питання досі не додано останнього синтаксису, додавши мої 2 центи.

Скажімо, у нас є масив об’єктів arrObj, і ми хочемо шукати в ньому obj.

Масив.прототип 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

Масив.прототип включає -> (повертає істинне чи помилкове )

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

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

Масив.прототип find -> (приймає зворотний виклик, повертає перше значення / об'єкт, який повертає true у ЦБ).

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

Масив.прототип findIndex -> (приймає зворотний виклик, повертає індекс першого значення / об'єкта, який повертає істинну в ЦБ).

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

якщо дані недійсні, то немає адміністратора, інакше він поверне існуючий об'єкт, як показано нижче.

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