javascript - includes - js check if array contains element




Come posso verificare se un array include un oggetto in JavaScript? (20)

Qual è il modo più conciso ed efficace per scoprire se una matrice JavaScript contiene un oggetto?

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 realizzare questo?

Questo è strettamente correlato alla domanda Stack Overflow Il modo migliore per trovare un elemento in un array JavaScript? che si occupa di trovare oggetti in un array usando indexOf .


Come altri hanno menzionato, puoi utilizzare Array.indexOf , ma non è disponibile in tutti i browser. Ecco il codice da https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf per farlo funzionare allo stesso modo nei browser più vecchi.

indexOf è una recente aggiunta allo standard ECMA-262; in quanto tale potrebbe non essere presente in tutti i browser. È possibile aggirare questo problema inserendo il seguente codice all'inizio degli script, consentendo l'uso di indexOf nelle implementazioni che non lo supportano in modo nativo. Questo algoritmo è esattamente quello specificato in ECMA-262, 5a edizione, assumendo Object, TypeError, Number, Math.floor, Math.abs e Math.max hanno il loro valore originale.

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's 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;
    }
}

ECMAScript 6 ha una proposta elegante sul trovare.

Il metodo find esegue la funzione di callback una volta per ciascun elemento presente nell'array finché non ne trova uno in cui il callback restituisce un valore true. Se viene trovato un tale elemento, find restituisce immediatamente il valore di quell'elemento. Altrimenti, trova i ritorni indefiniti. la callback è invocata solo per gli indici dell'array che hanno assegnato valori; non è invocato per gli indici che sono stati cancellati o che non sono mai stati assegnati valori.

Ecco la documentazione MDN su questo.

La funzionalità di ricerca funziona così.

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 utilizzare questo in ECMAScript 5 e sotto 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;
    }
  });
}

Ecco come Prototype lo fa :

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

Vedi anche here per come lo collegano.


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

I browser correnti includono l' Array#includes , che fa esattamente questo, è ampiamente supportato e ha un polyfill per i browser più vecchi.

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

È inoltre possibile utilizzare l' Array#indexOf , che è meno diretto, ma non richiede Polyfills per i browser non aggiornati.

jQuery offre $.inArray , che è funzionalmente equivalente a Array#indexOf .

underscore.js , una libreria di utilità JavaScript, offre _.contains(list, value) , alias _.include(list, value) , che utilizzano internamente indexOf se passano un array JavaScript.

Alcuni altri framework offrono metodi simili:

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


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

Mentre array.indexOf(x)!=-1 è il modo più conciso per farlo (ed è stato supportato da browser non Internet Explorer per oltre dieci anni ...), non è O (1), ma piuttosto O ( N), che è terribile. Se il tuo array non cambierà, puoi convertire il tuo array in un hashtable, quindi table[x]!==undefined o ===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 è possibile creare un Array.prototype.contains per "congelare" un array e memorizzare un hashtable in this._cache in due righe, ciò darebbe risultati errati se si decidesse di modificare l'array in un secondo momento. per esempio, tieni questo stato, diversamente da Python.)


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


Puoi anche usare questo trucco:

var arrayContains = function(object) {
  return (serverList.filter(function(currentObject) {
    if (currentObject === object) {
      return currentObject
    }
    else {
      return false;
    }
  }).length > 0) ? true : false
}

Se stai usando JavaScript 1.6 o successivo (Firefox 1.5 o successivo) puoi usare Array.indexOf . Altrimenti, penso che finirai con qualcosa di simile al tuo codice originale.


Si può usare Set che ha il metodo "ha ()":

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

Usa some funzioni di lodash.

È conciso, accurato e ha un ottimo supporto multipiattaforma.

La risposta accettata non soddisfa nemmeno i requisiti.

Requisiti: consiglia il modo più conciso ed efficace per scoprire se una matrice 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

Gli appunti:

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

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

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

Per gestire sia scalari che oggetti, puoi fare ciò:

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

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

Uso:

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

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


b è il valore e a è la matrice. Restituisce true o false :

function(a, b) {
    return a.indexOf(b) != -1
}

Aggiornamento: come @orip menziona nei commenti, il benchmark collegato è stato fatto nel 2008, quindi i risultati potrebbero non essere rilevanti per i browser moderni. Tuttavia, probabilmente hai bisogno di questo per supportare comunque i browser non moderni e probabilmente non sono stati aggiornati da allora. Prova sempre per te stesso.

Come altri hanno già detto, l'iterazione attraverso l'array è probabilmente il modo migliore, ma è stato dimostrato che un ciclo while diminuzione è il modo più veloce per scorrere 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

Non è affatto il migliore, ma mi stavo solo creando e aggiungendo 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'));


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

Array.prototype.some() stato aggiunto allo standard ECMA-262 nella quinta edizione





browser