Come posso verificare se un array include un valore in JavaScript?


3997

Qual è il modo più conciso ed efficiente per scoprire se un array JavaScript contiene un valore?

Questo è l'unico modo che conosco per farlo:

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

C'è un modo migliore e più conciso per raggiungere questo obiettivo?

Questo è strettamente correlato alla domanda di overflow dello stack. Il modo migliore per trovare un elemento in un array JavaScript? che indirizza la ricerca di oggetti in un array utilizzando indexOf.


49
appena testato: la tua strada è in realtà la più veloce per tutti i browser: jsperf.com/find-element-in-obj-vs-array/2 (a parte pre-salvare a.length in una variabile) mentre usi indexOf (come in $ .inArray) è molto più lento
Jörn Berkefeld il

17
molti hanno risposto che Array # indexOf è la scelta migliore qui. Ma se vuoi qualcosa che può essere correttamente castato su Booleano, usa questo: ~[1,2,3].indexOf(4)restituirà 0 che valuterà come falso, mentre ~[1,2,3].indexOf(3)restituirà -3 che valuterà come vero.
Lordvlad,

8
~non è quello che vuoi usare per convertire in un valore booleano, per quello che ti serve !. Ma in questo caso vuoi verificare l'uguaglianza con -1, quindi la funzione potrebbe finire non return [1,2,3].indexOf(3) === -1; ~è un binario, invertirà ogni bit del valore singolarmente.
mcfedr,

14
@Iordvlad restituirà[1,2,3].indexOf(4) effettivamente -1 . Come ha sottolineato @mcfedr, ~è l' operatore bit-NOT , vedi ES5 11.4.8. Il fatto è che, poiché la rappresentazione binaria di -1consiste solo di 1, il suo complemento è 0, che viene valutato come falso. Il complemento di qualsiasi altro numero sarà diverso da zero, quindi vero. Quindi, ~funziona bene ed è spesso usato insieme a indexOf.
mknecht,

5
Il titolo è fuorviante. Dov'è il [[1,2],[3,4]].includes([3,4])?
mplungjan,

Risposte:


4379

I browser moderni hanno Array#includes, che fa esattamente questo ed è ampiamente supportato da tutti tranne IE:

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

Puoi anche usare Array#indexOf, che è meno diretto, ma non richiede i riempimenti poligonali per i browser obsoleti.


Molti framework offrono anche metodi simili:

Si noti che alcuni framework implementano questa funzione come funzione, mentre altri aggiungono la funzione al prototipo di array.


42
MooTools ha anche Array.contains che restituisce un valore booleano, che suona come la vera domanda qui.
Ryan Florence,

22
ha anche un prototipo Array.includeche restituisce un valore booleano
user102008,

46
Se stai usando un buon browser, puoi semplicemente usarearray.indexOf(object) != -1
Sam Soffes,

13
Inoltre, l'uso Dont indexOf da solo come una condizione, perché il primo elemento tornerà 0 e verrà valutata come falsy
plus-

241
inArrayè un nome terribile per una funzione che restituisce l'indice dell'elemento e -1se non esiste. Mi aspetterei un ritorno booleano.
Tim

434

Aggiornamento dal 2019: questa risposta è del 2008 (11 anni!) E non è rilevante per l'utilizzo moderno di JS. Il miglioramento delle prestazioni promesso si basava su un benchmark fatto nei browser di quel tempo. Potrebbe non essere rilevante per i moderni contesti di esecuzione di JS. Se hai bisogno di una soluzione semplice, cerca altre risposte. Se hai bisogno delle migliori prestazioni, esegui il benchmark per te negli ambienti di esecuzione pertinenti.

Come altri hanno già detto, l'iterazione attraverso l'array è probabilmente il modo migliore, ma è stato dimostrato che un whileciclo decrescente è il modo più veloce per iterare in JavaScript. Quindi potresti voler riscrivere il tuo codice come segue:

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

Naturalmente, puoi anche estendere il prototipo di array:

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

E ora puoi semplicemente usare quanto segue:

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


22
"Comprovato" è una parola forte. I motori JS migliorano costantemente e il tempo di esecuzione misurato 3 anni fa è terribilmente obsoleto.
Orip,

2
@Damir - Sono d'accordo. Forse cambia l'esempio per usare indexOf se disponibile, solo così le persone che incollano questo codice alla cieca otterranno le migliori prestazioni possibili.
Orip,

1
@cbmeeks sì, la cura è sicuramente necessaria. Probabilmente è stato un caso di fare for (o in array)che non dovrebbe essere fatto quando si fa un loop nell'array in generale ...
Damir Zekić,

1
Il modo migliore per farlo è verificare se [1, 2, 3] .indexOf (1)> -1
Devin G Rhode,

207

indexOf forse, ma è "un'estensione JavaScript allo standard ECMA-262; come tale potrebbe non essere presente in altre implementazioni dello standard."

Esempio:

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

AFAICS Microsoft non offre alcun tipo di alternativa a questo, ma è possibile aggiungere funzionalità simili agli array in Internet Explorer (e altri browser che non supportano indexOf) se si desidera, come rivela una rapida ricerca su Google (ad esempio, questo ).


in realtà, c'è un esempio dell'implementazione dell'estensione indexOf per i browser che non lo supportano nella pagina developer.mozilla.org a cui si è collegati.
Lloyd Cotten,

in realtà, se si aggiunge indexof al prototipo di array per browser che non lo supportano (ad es. IE7), proveranno anche a eseguire il ciclo su questa funzione quando si eseguono il ciclo degli elementi dell'array. cattiva.
CpILL,


è applicabile per verificare l'oggetto. non penso che funzioni nel caso dell'Oggetto
Himesh Aadeshara,

169

ECMAScript 7 introduce Array.prototype.includes.

Può essere usato in questo modo:

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

Accetta anche un secondo argomento facoltativo fromIndex:

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

Diversamente indexOf, che utilizza Strict Equality Comparison , includesconfronta utilizzando l'algoritmo di uguaglianza SameValueZero . Ciò significa che è possibile rilevare se un array include un NaN:

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

Inoltre indexOf, a differenza di , includesnon salta gli indici mancanti:

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

Attualmente è ancora una bozza ma può essere polifillata per farlo funzionare su tutti i browser.


3
Non supportato per IE e Microsfot Edge (2015) ( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… )
Adriano Resende,

1
Anche pertinente, la tabella di compatibilità ES7 (sembra che Chrome lo supporti ora)
styfle

è applicabile per verificare l'oggetto. non penso che funzioni nel caso dell'Oggetto
Himesh Aadeshara,

128

Le risposte migliori assumono tipi primitivi ma se vuoi scoprire se un array contiene un oggetto con qualche tratto, Array.prototype.some () è una soluzione molto elegante:

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

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

La cosa bella è che l'iterazione viene interrotta una volta trovato l'elemento, in modo da risparmiare cicli di iterazione non necessari.

Inoltre, si adatta perfettamente a una ifdichiarazione poiché restituisce un valore booleano:

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

* Come sottolineato da jamess nel commento, al momento di questa risposta, settembre 2018, Array.prototype.some()è pienamente supportato: tabella di supporto caniuse.com


1
Ad oggi, settembre 2018, Array.prototype.some () è pienamente supportato: tabella di supporto
caniuse.com

1
Lavorare in Node> = 8.10 per AWS Node.js Lambda, quindi è fantastico. Soluzione molto pulita e semplice! 👍🏻
Giordania,

1
@jamess Potrebbe essere ben supportato, ma ricorda che Arrow functionsin questo esempio non sono così ben supportati. Per maggiori dettagli vedere qui: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Kamil Witkowski

Qualche corto circuito? O itera l'intero array anche se trova un valore?
Douglas Gaskell,

@DouglasGaskell interrompe l'iterazione una volta trovata (menzionata nella risposta)
Michael

112

Diciamo che hai definito un array in questo modo:

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

Di seguito sono riportati tre modi per verificare se è presente un file 3. Tutti ritornano trueo false.

Metodo array nativo (dal ES2016) ( tabella di compatibilità )

array.includes(3) // true

Come metodo di array personalizzato (pre 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

Funzione semplice

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

Restituisce vero se "b" è nella matrice "a" ... Non so come spiegarlo
diversamente

4
Questa parte non capisco "!! ~". E penso che questo non funzionerà in IE8 perché IE8 non supporta indexOf () sull'oggetto Array.
svlada,

62
"~" è un operatore che sposta, inverte e sottrae 1 da un numero. indexOf restituisce -1 se fallisce, quindi "~" trasforma -1 in "0". usando "!!" trasforma i numeri in boleani (!! 0 === falso)
william malo,

1
Fantastico, ma seriamente per semplicità, non solo a.indexOf (b)> - 1, dal momento che "> -1" .length === "!! ~" .length
super

2
Definirei la mancanza di conoscenza degli effetti degli operatori booleani non professionale. Ma sono d'accordo sul valore del codice leggibile, lo avvolgerò sicuramente in una funzione chiaramente etichettata. Ed è esattamente ciò che fanno i principali framework JS.
Okdewit,

79

Ecco un'implementazione compatibile con JavaScript 1.6 di 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;
        };
}

Sembra fantastico, ma un po 'confuso: * I test sulle linee 1 e 3 non sono equivalenti? * Non sarebbe meglio testare il prototipo e aggiungere la funzione ad Array.prototype se necessario?
Avi Flax,

10
Non sono equivalenti. [].indexOfè una scorciatoia per Array.prototype.indexOf. Noi programmatori Javascript difensori paranoici evitiamo di estendere i prototipi nativi a tutti i costi.
Már Örlygsson,

1
Non è [].indexOfla creazione di un nuovo array e poi accedendo indexOf, mentre Array.prototype.indexOfsolo accede direttamente il prototipo?
alex

3
@alex yes [].indexOf === Array.prototype.indexOf(provalo in FireBug), ma al contrario [].indexOf !== Array.indexOf.
Már Örlygsson,

57

Uso:

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

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

25
x ? true : falseè generalmente ridondante. È qui.
Ry-

@minitech Perché dici che è ridondante?
Matías Cánepa,

8
array.indexOf(search) >= 0è già un booleano. Basta return array.indexOf(search) >= 0.
Ry-

@minitech bene grazie! In realtà non sapevo che una simile costruzione potesse essere restituita. TIL qualcosa di nuovo.
Matías Cánepa,

Letteralmente qualsiasi costrutto in javascript può essere restituito
BT

49

L'estensione Arraydell'oggetto JavaScript è una pessima idea perché si introducono nuove proprietà (i metodi personalizzati) in for-incicli che possono spezzare gli script esistenti. Alcuni anni fa gli autori della biblioteca Prototype hanno dovuto riprogettare l'implementazione della loro biblioteca per rimuovere proprio questo genere di cose.

Se non devi preoccuparti della compatibilità con altri JavaScript in esecuzione sulla tua pagina, provaci, altrimenti, consiglierei la soluzione di funzione indipendente più scomoda, ma più sicura.


22
Non sono d'accordo. I loop di for-in non devono essere utilizzati per gli array proprio per questo motivo. L'uso dei loop for-in si interromperà quando si utilizza una delle librerie js più popolari
Tomas,

Questo sarebbe considerato patch di scimmia? lol Ad alcune persone piace.
cbmeeks,

33

One-liner:

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

8
array.filter(e=>e==x).length > 0è equivalente array.some(e=>e==x)ma someè più efficiente
Apolo


28

Io uso il seguente:

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

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

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


19

Un bidirezionale indexOf/ lastIndexOfalternativa si spera più veloce

2015

Mentre il nuovo metodo include è molto bello, il supporto è praticamente zero per ora.

È da molto tempo che pensavo al modo di sostituire le funzioni slow indexOf / lastIndexOf.

È già stato trovato un modo performante, guardando le risposte migliori. Tra quelli ho scelto la containsfunzione pubblicata da @Damir Zekic che dovrebbe essere la più veloce. Ma afferma anche che i parametri di riferimento sono del 2008 e quindi sono obsoleti.

Preferisco anche whileover for, ma per un motivo non specifico ho finito di scrivere la funzione con un ciclo for. Potrebbe anche essere fatto con awhile -- .

Ero curioso di sapere se l'iterazione era molto più lenta se controllo entrambi i lati dell'array mentre lo faccio. Apparentemente no, e quindi questa funzione è circa due volte più veloce di quelle più votate. Ovviamente è anche più veloce di quello nativo. Questo in un ambiente del mondo reale, dove non si sa mai se il valore che si sta cercando è all'inizio o alla fine dell'array.

Quando sai che hai appena spinto un array con un valore, usare lastIndexOf rimane probabilmente la soluzione migliore, ma se devi viaggiare attraverso grandi array e il risultato potrebbe essere ovunque, questa potrebbe essere una soluzione solida per rendere le cose più veloci.

Indice bidirezionaleOf / 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');

Test della prestazione

http://jsperf.com/bidirectionalindexof

Come test ho creato un array con 100k voci.

Tre query: all'inizio, al centro e alla fine dell'array.

Spero che anche tu lo trovi interessante e testare le prestazioni.

Nota: Come puoi vedere, ho leggermente modificato la containsfunzione per riflettere l'output indexOf e lastIndexOf (quindi sostanzialmente truecon indexe falsecon -1). Questo non dovrebbe danneggiarlo.

La variante del prototipo di array

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

La funzione può anche essere facilmente modificata per restituire vero o falso o persino l'oggetto, la stringa o qualunque cosa sia.

Ed ecco la whilevariante:

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

Com'è possibile?

Penso che il semplice calcolo per ottenere l'indice riflesso in un array sia così semplice che è due volte più veloce rispetto a eseguire un'iterazione di loop effettiva.

Ecco un esempio complesso che esegue tre controlli per iterazione, ma ciò è possibile solo con un calcolo più lungo che provoca il rallentamento del codice.

http://jsperf.com/bidirectionalindexof/2


18

Prestazione

Oggi 2020.01.07 eseguo test su MacO HighSierra 10.13.6 su Chrome v78.0.0, Safari v13.0.4 e Firefox v71.0.0 per 15 soluzioni scelte. conclusioni

  • soluzioni riferiscono JSON, Sete sorprendentemente find(K, N, O) sono più lenta su tutti i browser
  • es6 includes(F) è veloce solo su Chrome
  • le soluzioni basate su for(C, D) e indexOf(G, H) sono abbastanza veloci su tutti i browser su array piccoli e grandi, quindi probabilmente sono la scelta migliore per una soluzione efficiente
  • le soluzioni in cui l'indice diminuisce durante il ciclo, (B) è più lenta probabilmente perché funziona la cache della CPU .
  • Eseguo anche test per array di grandi dimensioni quando l'elemento cercato era nella posizione 66% della lunghezza dell'array e soluzioni basate su for(C, D, E) forniscono risultati simili (~ 630 ops / sec - ma l'E su safari e firefox era 10- 20% più lento di C e D)

risultati

inserisci qui la descrizione dell'immagine

Dettagli

Eseguo 2 casi di test: per array con 10 elementi e array con 1 milione di elementi. In entrambi i casi mettiamo l'elemento cercato nel mezzo dell'array.

Matrice piccola - 10 elementi

È possibile eseguire i test nella propria macchina QUI

inserisci qui la descrizione dell'immagine

Matrice grande - 1.000.000 di elementi

È possibile eseguire i test nella propria macchina QUI

inserisci qui la descrizione dell'immagine


16

Se si utilizza JavaScript 1.6 o versioni successive (Firefox 1.5 o versioni successive) è possibile utilizzare Array.indexOf . Altrimenti, penso che finirai con qualcosa di simile al tuo codice originale.


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

Restituisce l'indice dell'array se trovato o -1 se non trovato


16

Usiamo questo frammento (funziona con oggetti, matrici, stringhe):

/*
 * @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
});

Uso:

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

Se stai verificando ripetutamente l'esistenza di un oggetto in un array, dovresti forse esaminare

  1. Mantenere l'array sempre ordinato eseguendo l'ordinamento di inserzione nell'array (posiziona i nuovi oggetti nel posto giusto)
  2. Effettua l'aggiornamento degli oggetti come rimuovi + operazione di inserimento ordinata e
  3. Usa una ricerca binaria nel tuo contains(a, obj).

2
O, se possibile, smettere di usare completamente un array e utilizzare invece un oggetto come dizionario, come hanno suggerito MattMcKnight e ninjagecko.
joeytwiddle,

13

Soluzione che funziona in tutti i browser moderni:

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

Uso:

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

Soluzione 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;
  };
}

Uso:

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

Perché usare JSON.stringify?

Array.indexOfe Array.includes(oltre alla maggior parte delle risposte qui) confronta solo per riferimento e non per valore.

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

indennità

One-liner ES6 non ottimizzato:

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

Nota: il confronto degli oggetti in base al valore funzionerà meglio se le chiavi sono nello stesso ordine, quindi per sicurezza puoi prima ordinare le chiavi con un pacchetto come questo: https://www.npmjs.com/package/sort-keys


Aggiornato la containsfunzione con un'ottimizzazione perf. Grazie itinance per segnalarlo.


Questo particolare blocco di codice può funzionare in IE6 (non è stato testato), ma IE non supporta ES5 fino a IE9.
Mark Reed,

Per motivi di prestazioni dovresti evitare di stringere. Almeno dovresti evitare di JSON.stringify "obj" su ogni loop perché è costoso e rallenterà la tua applicazione. Quindi dovresti catturarlo prima del for-loop in una variabile temp
itinance

1
@itinance buon punto. Aggiornato la includesfunzione con il tuo suggerimento. Ho eseguito jsperf con la mia funzione. È circa 5 volte più lento di quello di lodash. Anche se lodash non è paragonabile per valore e non riesce a trovare {a: 1}in [{a: 1}]. Non so se c'è qualche biblioteca. Ma sono curioso di sapere se esiste un modo più performante e non follemente complesso di farlo.
Igor Barbashin,

Nota in ritardo: questo non funziona, diciamo, contains([{ a: 1, b: 2 }], { b: 2, a: 1 })perché gli oggetti sottoposti a stringere mantengono l'ordine delle proprietà.
Heretic Monkey,

1
@HereticMonkey, true. Ecco perché ho aggiunto la sort-keysnota in fondo
Igor Barbashin,

12

Usa lodash è una funzione.

È conciso, preciso e ha un ottimo supporto multipiattaforma.

La risposta accettata non soddisfa nemmeno i requisiti.

Requisiti: consiglia il modo più conciso ed efficiente per scoprire se un array JavaScript contiene un oggetto.

Risposta accettata:

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

La mia raccomandazione:

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

Appunti:

$ .inArray funziona bene per determinare se esiste un valore scalare in una matrice di scalari ...

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

... ma la domanda richiede chiaramente un modo efficiente per determinare se un oggetto è contenuto in un array.

Per gestire sia gli scalari che gli oggetti, puoi fare questo:

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

10

ECMAScript 6 ha una proposta elegante da trovare.

Il metodo find esegue la funzione di callback una volta per ogni elemento presente nell'array fino a quando non ne trova uno in cui callback restituisce un valore vero. Se viene trovato un tale elemento, find restituisce immediatamente il valore di quell'elemento. Altrimenti, trova i rendimenti non definiti. il callback viene richiamato solo per gli indici dell'array a cui sono stati assegnati valori; non viene invocato per gli indici che sono stati eliminati o ai quali non sono mai stati assegnati valori.

Ecco la documentazione MDN su questo.

La funzionalità di ricerca funziona in questo modo.

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

È possibile utilizzarlo in ECMAScript 5 e seguenti definendo la funzione .

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

Mentre array.indexOf(x)!=-1è il modo più conciso per farlo (ed è supportato da browser non Internet Explorer da oltre un decennio ...), non è O (1), ma piuttosto O (N), che è terribile. Se il tuo array non cambierà, puoi convertirlo in un hashtable, quindi fai table[x]!==undefinedo ===undefined:

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

demo:

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

(Sfortunatamente, mentre puoi creare un Array.prototype.contains per "congelare" un array e archiviare un hashtable in this._cache in due righe, questo darebbe risultati errati se scegli di modificare il tuo array in un secondo momento. JavaScript ha hook insufficienti per ti consente di mantenere questo stato, a differenza di Python per esempio.)


9

Si può usare Set che ha il metodo "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
Penso che return proxy.has(obj)sia molto più pulito di due righe con l'istruzione if-else qui
Maciej Bukowski,

function contains(arr, obj) { return new Set(arr).has(obj); }
Gordon Bean,

8

Uso:

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

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

dimostrazione

Per sapere esattamente cosa tilde ~fanno a questo punto, fai riferimento a questa domanda Cosa fa una tilde quando precede un'espressione? .


5
Questo è già stato pubblicato un anno e mezzo fa, non è necessario ripeterlo.
Shadow Wizard is Ear For You,

3
In realtà, non è stato pubblicato. Non come una risposta, ma come un commento a una risposta, e anche allora non è chiaro e conciso. Grazie per averlo pubblicato, Mina Gabriel.
T.CK

6

OK, puoi semplicemente ottimizzare il tuo codice per ottenere il risultato!

Ci sono molti modi per farlo che sono più puliti e migliori, ma volevo solo ottenere il tuo modello e applicarlo a quello usando JSON.stringify, semplicemente fai qualcosa di simile nel tuo caso:

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

Nota in ritardo: questo non funziona, diciamo, contains([{ a: 1, b: 2 }], { b: 2, a: 1 })perché gli oggetti sottoposti a stringere mantengono l'ordine delle proprietà.
Heretic Monkey,

5

Non è affatto il migliore, ma stavo solo diventando creativo e aggiungevo al repertorio.

Non usare questo

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


Cosa dovresti usare se non questo?
bryc,

@bryc forse la soluzione accettata o un'altra soluzione da qui. Se non ti importa molto delle prestazioni, allora puoi usarlo
sqram

5

Sorpreso che questa domanda non abbia ancora aggiunto l'ultima sintassi, aggiungendo i miei 2 centesimi.

Diciamo che abbiamo una serie di oggetti arrObj e vogliamo cercare obj in esso.

Array.prototype. indexOf -> (restituisce index o -1 ) viene generalmente utilizzato per trovare l'indice dell'elemento nella matrice. Questo può essere utilizzato anche per la ricerca di oggetti, ma funziona solo se si passa riferimento allo stesso oggetto.

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


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

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

Array.prototype. include -> (restituisce vero o falso )

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

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

Array.prototype. find -> (accetta il callback, restituisce il primo valore / oggetto che restituisce true in CB).

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

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

Array.prototype. findIndex -> (accetta il callback, restituisce l' indice del primo valore / oggetto che restituisce true in CB).

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

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

Poiché find and findIndex accetta un callback, possiamo recuperare qualsiasi oggetto (anche se non abbiamo il riferimento) dall'array impostando in modo creativo la vera condizione.


5

Si sta utilizzando una soluzione semplice per questo requisito find()

Se hai una serie di oggetti come di seguito,

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

Quindi puoi verificare se l'oggetto con il tuo valore è già presente o meno

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

se i dati sono nulli allora nessun amministratore, altrimenti restituirà l'oggetto esistente come di seguito.

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

Quindi puoi trovare l'indice di quell'oggetto nella matrice e sostituire l'oggetto usando il codice seguente.

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

otterrai valore come di seguito

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

spero che questo possa aiutare chiunque.


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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.