¿Cómo verifico si una matriz incluye un valor en JavaScript?

4443

¿Cuál es la forma más concisa y eficiente de averiguar si una matriz de JavaScript contiene un valor?

Esta es la única forma que conozco de hacerlo:

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

¿Existe una forma mejor y más concisa de lograr esto?

10
  • 54
    recién probado: su camino es en realidad el más rápido para todos los navegadores: jsperf.com/find-element-in-obj-vs-array/2 (además de guardar previamente a.length en una variable) mientras usa indexOf (como en $ .inArray) es mucho más lento 02/07/12 a las 11:56
  • 18
    muchos han respondido que Array # indexOf es su mejor opción aquí. Pero si desea algo que se pueda convertir correctamente en booleano, use esto: ~[1,2,3].indexOf(4)devolverá 0 que se evaluará como falso, mientras ~[1,2,3].indexOf(3)que devolverá -3 que se evaluará como verdadero. 2 oct 2013 a las 7:59
  • 9
    ~no es lo que desea usar para convertir a booleano, para eso lo necesita !. Pero en este caso, desea verificar la igualdad con -1, por lo que la función podría terminar en return [1,2,3].indexOf(3) === -1; ~un no binario, invertirá cada bit del valor individualmente.
    mcfedr
    20 de junio de 2014 a las 12:49
  • dieciséis
    @Iordvlad en [1,2,3].indexOf(4)realidad devolverá -1 . Como señaló @mcfedr, ~es el operador bit a bit , consulte ES5 11.4.8. La cuestión es que, dado que la representación binaria de -1consta de solo unos, su complemento es 0, que se evalúa como falso. El complemento de cualquier otro número será distinto de cero, por lo tanto, verdadero. Por lo tanto, ~funciona bien y a menudo se usa junto con indexOf.
    mknecht
    14 de marzo de 2015 a las 5:35
  • 6
    El título es engañoso. ¿Dónde está el [[1,2],[3,4]].includes([3,4])? 2/04/2017 a las 9:20
4897

Los navegadores modernos tienen Array#includes, que hace exactamente eso y es ampliamente compatible con todos excepto IE:

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

También puede usar Array#indexOf, que es menos directo, pero no requiere polyfills para navegadores obsoletos.

console.log(['joe', 'jane', 'mary'].indexOf('jane') >= 0); //true

Muchos marcos también ofrecen métodos similares:

Tenga en cuenta que algunos marcos implementan esto como una función, mientras que otros agregan la función al prototipo de matriz.

25
  • 45
    MooTools también tiene Array.contains que devuelve un booleano, que suena como la verdadera pregunta aquí. 8/06/10 a las 14:10
  • 23
    el prototipo también tiene Array.includeque devuelve un booleano 10/09/10 a las 22:54
  • 47
    Si está utilizando un buen navegador, puede usar array.indexOf(object) != -1 6/10/10 a las 16:17
  • 14
    Además, no use indexOf solo como condición, porque el primer elemento devolverá 0 y se evaluará como falso
    plus-
    29/02/12 a las 17:17
  • 253
    inArrayes un nombre terrible para una función que devuelve el índice del elemento, y -1si no existe. Esperaría que se devolviera un booleano.
    Tim
    22/07/12 a las 9:45
471

Actualización de 2019: esta respuesta es de 2008 (¡11 años!) Y no es relevante para el uso moderno de JS. La mejora de rendimiento prometida se basó en un punto de referencia realizado en navegadores de esa época. Puede que no sea relevante para los contextos de ejecución de JS modernos. Si necesita una solución sencilla, busque otras respuestas. Si necesita el mejor rendimiento, realice una evaluación comparativa en los entornos de ejecución relevantes.

Como han dicho otros, la iteración a través de la matriz es probablemente la mejor manera, pero se ha demostrado que un whilebucle decreciente es la forma más rápida de iterar en JavaScript. Por lo tanto, es posible que desee reescribir su código de la siguiente manera:

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

Por supuesto, también puede extender el prototipo Array:

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

Y ahora simplemente puede usar lo siguiente:

alert([1, 2, 3].contains(2)); // => true
alert([1, 2, 3].contains('2')); // => false
15
  • 25
    Pero tenga cuidado: stackoverflow.com/questions/237104/javascript-array-containsobj/… 12 de agosto de 2010 a las 23:16
  • 25
    "Probado" es una palabra fuerte. Los motores JS mejoran constantemente y el tiempo de ejecución medido hace 3 años está terriblemente desactualizado.
    orip
    20/11/11 a las 8:09
  • 2
    @ Damir - Estoy de acuerdo. Quizás cambie la muestra para usar indexOf si está disponible, solo para que las personas que copian y pegan este código a ciegas obtengan el mejor rendimiento posible.
    orip
    20/11/11 a las 12:45
  • 1
    @cbmeeks sí, definitivamente se necesita cuidado. Probablemente fue un caso de hacer for (o in array)lo que no debería hacerse al recorrer la matriz en general ... 12/10/12 a las 13:18
  • 1
    La mejor forma de hacerlo es comprobar si [1, 2, 3] .indexOf (1)> -1 28/10/12 a las 23:25
226

indexOf tal vez, pero es una "extensión JavaScript del estándar ECMA-262; como tal, puede que no esté presente en otras implementaciones del estándar".

Ejemplo:

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

AFAICS Microsoft no ofrece ningún tipo de alternativa a esto, pero puede agregar una funcionalidad similar a las matrices en Internet Explorer (y otros navegadores que no son compatibles indexOf) si lo desea, como revela una búsqueda rápida de Google (por ejemplo, este ).

4
  • de hecho, hay un ejemplo de la implementación de la extensión indexOf para navegadores que no la admiten en la página developer.mozilla.org a la que se vinculó. 24 mar 09 a las 21:24
  • 1
    en realidad, si agrega indexof al prototipo de Array para navegadores que no lo soportan (es decir, IE7), también intentarán recorrer esta función al recorrer los elementos de la matriz. desagradable.
    CpILL
    11/07/12 a las 9:13
  • 4
    IE9 ahora es compatible con esto
    Liam
    29 de mayo de 2014 a las 14:33
  • ¿Es aplicable verificar el Objeto? no creo que funcione en el caso del objeto 25 de mayo de 2018 a las 4:19
184

Se presenta ECMAScript 7 Array.prototype.includes.

Se puede usar así:

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

También acepta un segundo argumento opcional fromIndex:

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

A diferencia de indexOf, que usa la comparación estricta de igualdad , se includescompara con el algoritmo de igualdad SameValueZero . Eso significa que puede detectar si una matriz incluye NaN:

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

Además indexOf, a diferencia de , includesno omite los índices faltantes:

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

Actualmente todavía es un borrador, pero se puede rellenar para que funcione en todos los navegadores.

3
177

Las respuestas principales asumen tipos primitivos, pero si desea averiguar si una matriz contiene un objeto con algún rasgo, Array.prototype.some () es una solución 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

Lo bueno de esto es que la iteración se aborta una vez que se encuentra el elemento, por lo que se evitan los ciclos de iteración innecesarios.

Además, encaja muy bien en una ifdeclaración ya que devuelve un booleano:

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

* Como señaló jamess en el comentario, en el momento de esta respuesta, septiembre de 2018, Array.prototype.some()es totalmente compatible: tabla de soporte de caniuse.com

5
  • 2
    A partir de hoy, septiembre de 2018, Array.prototype.some () es totalmente compatible: tabla de soporte caniuse.com
    jamess
    14/09/18 a las 22:03
  • 2
    Trabajando en Node> = 8.10 para AWS Node.js Lambda, esto es genial. ¡Solución muy limpia y sencilla! 👍🏻
    Jordan
    20 de septiembre de 2018 a las 22:48
  • 2
    @jamess Puede que esté bien soportado, pero recuerda que Arrow functionsen este ejemplo no están tan bien soportados. Para obtener más detalles, consulte aquí: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… 24/01/19 a las 14:32
  • ¿Tiene algún cortocircuito? ¿O itera toda la matriz incluso si encuentra un valor? 3 oct 2019 a las 0:06
  • @DouglasGaskell aborta la iteración una vez encontrada (mencionada en la respuesta)
    Michael
    14/10/19 a las 12:28
118

Digamos que ha definido una matriz así:

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

A continuación, se muestran tres formas de comprobar si hay una 3. Todos regresan trueo false.

Método Native Array (desde ES2016) ( tabla de compatibilidad )

array.includes(3) // true

Como método de matriz personalizado (anterior a 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

Función simple

const includes = (a, v) => a.indexOf(v) !== -1
includes(array, 3) // true
5
  • Devuelve verdadero si "b" está en la matriz "a" ... No sé de qué otra manera explicarlo ... 16/06/12 a las 0:41
  • 4
    Esta parte no la entiendo "!! ~". Y creo que esto no funcionará en IE8 porque IE8 no es compatible con indexOf () en el objeto Array.
    svlada
    18/06/12 a las 5:29
  • 63
    "~" es un operador que pisos, invierte y resta 1 de un número. indexOf devuelve -1 si falla, por lo que "~" convierte -1 en "0". utilizando "!!" convierte números en boleanos (!! 0 === falso) 19/06/12 a las 14:41
  • 1
    Genial, pero en serio por simplicidad y no solo a.indexOf (b)> - 1, ya que "> -1" .length === "!! ~" .length
    user2039981
    16/12/14 a las 15:35
  • 2
    Yo llamaría poco profesional a la falta de conocimiento sobre los efectos de los operadores booleanos. Pero estoy de acuerdo sobre el valor del código legible, ciertamente lo envolvería en una función claramente etiquetada. Y eso es exactamente lo que hacen la mayoría de los principales marcos de JS.
    okdewit
    19 de enero de 2016 a las 11:18
83

Aquí hay una implementación compatible con JavaScript 1.6 de 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;
        };
}
4
  • Esto se ve muy bien, pero un poco confuso: * ¿No son equivalentes las pruebas de las líneas 1 y 3? * ¿No sería mejor probar el prototipo y agregar la función a Array.prototype si fuera necesario? 11/07/10 a las 12:31
  • 12
    No son equivalentes. [].indexOfes una abreviatura de Array.prototype.indexOf. Nosotros, los programadores de Javascript defensivos paranoicos evitamos extender los prototipos nativos a toda costa. 14 de julio de 2010 a las 12:03
  • 2
    ¿No es [].indexOfcrear una nueva matriz y luego acceder indexOf, mientras que Array.prototype.indexOfsimplemente accede al prototipo directamente?
    alex
    8/03/11 a las 11:47
  • 4
    @alex sí [].indexOf === Array.prototype.indexOf(pruébalo en FireBug), pero a la inversa [].indexOf !== Array.indexOf. 11/03/11 a las 13:32
59

Usar:

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

// Usage
if(isInArray(my_array, "my_value"))
{
    //...
}
5
  • 27
    x ? true : falsesuele ser redundante. Es aquí.
    Ry-
    26/02/2014 a las 16:38
  • 1
    @minitech ¿Por qué dices que es redundante? 3 de mayo de 2014 a las 15:40
  • 11
    array.indexOf(search) >= 0ya es un booleano. Solo return array.indexOf(search) >= 0.
    Ry-
    3 de mayo de 2014 a las 17:38
  • 1
    @minitech bueno gracias! En realidad, no sabía que una construcción así podría devolverse. HASTA algo nuevo. 29/07/14 a las 18:25
  • 2
    Literalmente, se puede devolver cualquier construcción en javascript.
    B T
    15/01/15 a las 22:20
53

Extender el Arrayobjeto JavaScript es una muy mala idea porque introduce nuevas propiedades (sus métodos personalizados) en for-inbucles que pueden romper los scripts existentes. Hace unos años, los autores de la biblioteca Prototype tuvieron que rediseñar la implementación de su biblioteca para eliminar este tipo de cosas.

Si no necesita preocuparse por la compatibilidad con otros JavaScript que se ejecutan en su página, hágalo, de lo contrario, le recomendaría la solución de función independiente más incómoda pero más segura.

2
  • 24
    Estoy en desacuerdo. Los bucles for-in no deben usarse para matrices precisamente por esta razón. El uso de bucles for-in se romperá al usar una de las bibliotecas js populares
    Tomas
    18/02/11 a las 14:51
  • 1
    ¿Se consideraría esto un parche de mono? lol A algunas personas les gusta eso.
    cbmeeks
    10/10/12 a las 20:36
35

Rendimiento

Hoy 2020.01.07 realizo pruebas en MacOs HighSierra 10.13.6 en Chrome v78.0.0, Safari v13.0.4 y Firefox v71.0.0 para 15 soluciones elegidas. Conclusiones

  • las soluciones basadas en JSON, Sety sorprendentemente find(K, N, O) son las más lentas en todos los navegadores
  • el es6 includes(F) es rápido solo en chrome
  • las soluciones basadas en for(C, D) y indexOf(G, H) son bastante rápidas en todos los navegadores en arreglos pequeños y grandes, por lo que probablemente sean la mejor opción para una solución eficiente
  • las soluciones donde el índice disminuye durante el ciclo, (B) es más lento probablemente porque funciona la forma de caché de la CPU .
  • También ejecuto una prueba para una gran matriz cuando el elemento buscado estaba en la posición 66% de la longitud de la matriz, y las soluciones basadas en for(C, D, E) dan resultados similares (~ 630 operaciones / seg, pero la E en safari y firefox era 10- 20% más lento que C y D)

Resultados

ingrese la descripción de la imagen aquí

Detalles

Realizo 2 casos de prueba: para matriz con 10 elementos y matriz con 1 millón de elementos. En ambos casos, colocamos el elemento buscado en el medio de la matriz.

let log = (name,f) => console.log(`${name}: 3-${f(arr,'s10')}  's7'-${f(arr,'s7')}  6-${f(arr,6)} 's3'-${f(arr,'s3')}`)

let arr = [1,2,3,4,5,'s6','s7','s8','s9','s10'];
//arr = new Array(1000000).fill(123); arr[500000]=7;

function A(a, val) {
    var i = -1;
    var n = a.length;
    while (i++<n) {
       if (a[i] === val) {
           return true;
       }
    }
    return false;
}

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

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

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

function E(a, val){  
  var n = a.length-1;
  var t = n/2;
  for (var i = 0; i <= t; i++) {
        if (a[i] === val || a[n-i] === val) return true;
  }
  return false;
}

function F(a,val) {
	return a.includes(val);
}

function G(a,val) {
	return a.indexOf(val)>=0;
}

function H(a,val) {
	return !!~a.indexOf(val);
}

function I(a, val) {
  return a.findIndex(x=> x==val)>=0;
}

function J(a,val) {
	return a.some(x=> x===val);
}

function K(a, val) {
  const s = JSON.stringify(val);
  return a.some(x => JSON.stringify(x) === s);
}

function L(a,val) {
	return !a.every(x=> x!==val);
}

function M(a, val) {
  return !!a.find(x=> x==val);
}

function N(a,val) {
	return a.filter(x=>x===val).length > 0;
}

function O(a, val) {
  return new Set(a).has(val);
}

log('A',A);
log('B',B);
log('C',C);
log('D',D);
log('E',E);
log('F',F);
log('G',G);
log('H',H);
log('I',I);
log('J',J);
log('K',K);
log('L',L);
log('M',M);
log('N',N);
log('O',O);
This shippet only presents functions used in performance tests - it not perform tests itself!

Matriz pequeña - 10 elementos

Puedes realizar pruebas en tu máquina AQUÍ

ingrese la descripción de la imagen aquí

Matriz grande - 1.000.000 elementos

Puedes realizar pruebas en tu máquina AQUÍ

ingrese la descripción de la imagen aquí

0
34

Un trazador de líneas:

function contains(arr, x) {
    return arr.filter(function(elem) { return elem == x }).length > 0;
}
1
  • 11
    array.filter(e=>e==x).length > 0es equivalente a array.some(e=>e==x)pero somees más eficiente
    Apolo
    22/04/2016 a las 9:22
33

Pensando fuera de la caja por un segundo, si está haciendo esta llamada muchas veces, es mucho más eficiente usar una matriz asociativa un Mapa para hacer búsquedas usando una función hash.

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

1
  • 1
    Aunque obviamente esto es útil para muchos, hubiera sido mejor si se hubiera agregado un fragmento de código. 11/12/18 a las 19:27
28

Yo uso lo siguiente:

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 () se agregó al estándar ECMA-262 en la quinta edición

2
  • si usa es6, entonces se puede acortar como contains = (a, obj) => a.some((element) => element === obj))
    diEcho
    28 de mayo de 2018 a las 4:24
  • Incluso IE9 tiene soporte para Array.prototype.some () a partir de ECMAScript 5 . 17/01/19 a las 17:45
19

Un bidireccional indexOf/ lastIndexOfalternativo con suerte más rápido

2015

Si bien el nuevo método incluye es muy bueno, el soporte es básicamente cero por ahora.

Hace mucho tiempo que estaba pensando en la forma de reemplazar las funciones lentas indexOf / lastIndexOf.

Ya se ha encontrado una forma de rendimiento, mirando las respuestas principales. De entre ellos, elegí la containsfunción publicada por @Damir Zekic, que debería ser la más rápida. Pero también establece que los puntos de referencia son de 2008 y, por lo tanto, están desactualizados.

También prefiero whileover for, pero no por una razón específica, terminé escribiendo la función con un bucle for. También se puede hacer con un while --.

Tenía curiosidad por saber si la iteración era mucho más lenta si verifico ambos lados de la matriz mientras lo hacía. Aparentemente no, por lo que esta función es aproximadamente dos veces más rápida que las más votadas. Obviamente también es más rápido que el nativo. Esto en un entorno del mundo real, donde nunca se sabe si el valor que está buscando está al principio o al final de la matriz.

Cuando sabe que acaba de insertar una matriz con un valor, usar lastIndexOf sigue siendo probablemente la mejor solución, pero si tiene que viajar a través de matrices grandes y el resultado podría estar en todas partes, esta podría ser una solución sólida para hacer las cosas más rápido.

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

Prueba de desempeño

http://jsperf.com/bidirectionalindexof

Como prueba, creé una matriz con 100k entradas.

Tres consultas: al principio, en el medio y al final de la matriz.

Espero que también encuentres esto interesante y pruebes el rendimiento.

Nota: Como puede ver, modifiqué ligeramente la containsfunción para reflejar la salida indexOf & lastIndexOf (básicamente truecon indexy falsecon -1). Eso no debería dañarlo.

La variante del prototipo de matriz

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 función también se puede modificar fácilmente para devolver verdadero o falso o incluso el objeto, la cadena o lo que sea.

Y aquí está 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');

¿Cómo es esto posible?

Creo que el cálculo simple para obtener el índice reflejado en una matriz es tan simple que es dos veces más rápido que hacer una iteración de bucle real.

Aquí hay un ejemplo complejo que hace tres comprobaciones por iteración, pero esto solo es posible con un cálculo más largo que provoca la ralentización del código.

http://jsperf.com/bidirectionalindexof/2

17

Si está utilizando JavaScript 1.6 o posterior (Firefox 1.5 o posterior) puede usar Array.indexOf . De lo contrario, creo que terminará con algo similar a su código original.

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

Devuelve el índice de la matriz si se encuentra, o -1 si no se encuentra

17

Usamos este fragmento (funciona con objetos, matrices, cadenas):

/*
 * @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
0
16

Si está comprobando repetidamente la existencia de un objeto en una matriz, tal vez debería investigar

  1. Mantener la matriz ordenada en todo momento haciendo una ordenación por inserción en su matriz (coloque nuevos objetos en el lugar correcto)
  2. Realice la actualización de objetos como operación de inserción eliminar + ordenada y
  3. Utilice una búsqueda de búsqueda binaria en su contains(a, obj).
1
  • 3
    O, si es posible, deje de usar una matriz por completo y, en su lugar, use un objeto como diccionario, como han sugerido MattMcKnight y ninjagecko. 8 de julio de 2013 a las 17:08
16

Solución que funciona en todos los navegadores modernos:

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

Solución 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

¿Por qué usarlo JSON.stringify?

Array.indexOfy Array.includes(así como la mayoría de las respuestas aquí) solo compare por referencia y no por valor.

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

Prima

Una sola línea ES6 no optimizada:

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

Nota: Comparar objetos por valor funcionará mejor si las claves están en el mismo orden, por lo que para estar seguro, puede ordenar las claves primero con un paquete como este: https://www.npmjs.com/package/sort-keys


Se actualizó la containsfunción con una optimización de rendimiento. Gracias itinance por señalarlo.

5
  • Este fragmento de código en particular puede funcionar en IE6 (no se ha probado), pero IE no admitió ES5 hasta IE9. 9/04/2017 a las 12:51
  • Por razones de rendimiento, debe evitar el encordado. Al menos debe evitar utilizar JSON. Stringificar el "obj" en cada bucle porque es caro y ralentizará su aplicación. Por lo tanto, debe capturarlo antes del bucle for en una variable temporal 14 de abril de 2017 a las 8:45
  • 2
    @itinance buen punto. Actualizó la includesfunción con su sugerencia. Ejecuté jsperf con mi función. Es aproximadamente 5 veces más lento de lo que incluye lodash. Aunque lodash no se compara por valor y no puede encontrar {a: 1}en [{a: 1}]. No sé si alguna biblioteca lo hace. Pero tengo curiosidad por saber si hay alguna forma más eficaz y no increíblemente compleja de hacerlo. 17 de abril de 2017 a las 4:57
  • Nota tardía: esto no funciona con, digamos, contains([{ a: 1, b: 2 }], { b: 2, a: 1 })porque los objetos en cadena mantienen el orden de las propiedades. 10/10/19 a las 15:10
  • 2
    @HereticMonkey, cierto. Por eso agregué la sort-keysnota al final 16/10/19 a las 17:44
12

Usa alguna función de Lodash .

Es conciso, preciso y tiene un gran soporte multiplataforma.

La respuesta aceptada ni siquiera cumple con los requisitos.

Requisitos: recomendar la forma más concisa y eficiente de averiguar si una matriz de JavaScript contiene un objeto.

Respuesta aceptada:

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

Mi recomendación:

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

Notas:

$ .inArray funciona bien para determinar si existe un valor escalar en una matriz de escalares ...

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

... pero la pregunta claramente pide una forma eficiente de determinar si un objeto está contenido en una matriz.

Para manejar escalares y objetos, puede hacer esto:

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

ECMAScript 6 tiene una elegante propuesta de búsqueda.

The find method executes the callback function once for each element present in the array until it finds one where callback returns a true value. If such an element is found, find immediately returns the value of that element. Otherwise, find returns undefined. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.

Aquí está la documentación de MDN sobre eso.

La funcionalidad de búsqueda funciona así.

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

Puede usar esto en ECMAScript 5 y siguientes definiendo la función .

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

Si bien array.indexOf(x)!=-1es la forma más concisa de hacer esto (y ha sido compatible con navegadores que no son de Internet Explorer durante más de una década ...), no es O (1), sino O (N), lo cual es terrible. Si su matriz no cambiará, puede convertir su matriz en una tabla hash, luego haga table[x]!==undefinedo ===undefined:

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

Manifestación:

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

(Desafortunadamente, aunque puede crear un Array.prototype.contains para "congelar" una matriz y almacenar una tabla hash en this._cache en dos líneas, esto daría resultados incorrectos si elige editar su matriz más tarde. JavaScript no tiene suficientes ganchos para le permite mantener este estado, a diferencia de Python, por ejemplo).

10

Uno puede usar Set que tiene el método "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
  • 8
    Creo que return proxy.has(obj)es mucho más limpio que dos líneas con una declaración if-else aquí 18 de agosto de 2016 a las 23:30
  • 1
    function contains(arr, obj) { return new Set(arr).has(obj); } 11 mar.20 a las 15:48
8

Usar:

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

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

Manifestación

Para saber exactamente qué tilde ~hacen en este punto, consulte esta pregunta ¿Qué hace una tilde cuando precede a una expresión? .

2
  • 6
    Esto ya se publicó hace año y medio, no es necesario repetirlo. 6/10/2013 a las 12:33
  • 4
    De hecho, no se ha publicado. No como una respuesta, sino como un comentario a una respuesta, e incluso entonces no es claro ni conciso. Gracias por publicarlo, Mina Gabriel.
    T.CK
    15 de mayo de 2018 a las 14:52
8

Una solución simple para este requisito es utilizar find()

Si tiene una variedad de objetos como a continuación,

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

Luego puede verificar si el objeto con su valor ya está presente o no

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

si los datos son nulos, entonces no hay administrador, de lo contrario, devolverá el objeto existente como se muestra a continuación.

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

Luego, puede encontrar el índice de ese objeto en la matriz y reemplazar el objeto usando el siguiente código.

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

obtendrás valor como a continuación

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

Espero que esto ayude a cualquiera.

7

De acuerdo, ¡puedes optimizar tu código para obtener el resultado!

Hay muchas formas de hacer esto que son más limpias y mejores, pero solo quería obtener su patrón y aplicarlo usando JSON.stringify, simplemente haga algo como esto en su 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;
}
1
  • 1
    Nota tardía: esto no funciona con, digamos, contains([{ a: 1, b: 2 }], { b: 2, a: 1 })porque los objetos en cadena mantienen el orden de las propiedades. 10/10/19 a las 15:12
7

Me sorprende que esta pregunta todavía no tenga la última sintaxis agregada, agregando mis 2 centavos.

Digamos que tenemos una matriz de Objetos arrObj y queremos buscar obj en ella.

Array.prototype. indexOf -> (devuelve índice o -1 ) generalmente se usa para encontrar el índice de un elemento en una matriz. Esto también se puede usar para buscar objetos, pero solo funciona si está pasando una referencia al mismo objeto.

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. incluye -> (devuelve verdadero 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. buscar -> (toma la devolución de llamada, devuelve el primer valor / objeto que devuelve verdadero en 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 -> (recibe devolución de llamada, devuelve el índice del primer valor / objeto que devuelve verdadero en 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

Dado que find y findIndex toman una devolución de llamada, podemos recuperar cualquier objeto (incluso si no tenemos la referencia) de la matriz estableciendo creativamente la condición verdadera.

6

De ninguna manera el mejor, pero me estaba volviendo creativo y agregando al repertorio.

No use esto

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'));
2
  • ¿Qué deberías usar si no es esto?
    bryc
    20/02/2017 a las 17:36
  • @bryc tal vez sea la solución aceptada, u otra solución de aquí. Si no te importa mucho el rendimiento, puedes usar este
    sqram
    16 de marzo de 2017 a las 19:49
6

Tiene un parámetro: una matriz de números de objetos. Cada objeto de la matriz tiene dos propiedades enteras indicadas por x e y. La función debe devolver un recuento de todos esos objetos en la matriz que satisfacennumbers.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 } ];
var count = 0; 
var n = numbers.length;
for (var i =0;i<n;i++)
{
  if(numbers[i].x==numbers[i].y)
    {count+=1;}
}

alert(count);
1
  • ¿Cómo compararías el valor de x con el valor x de los siguientes elementos? Esto no funciona:for (var i = 0; i < n; i++) { if (numbers[i].x == (numbers[i] + 1).x) { count += 1; } }
    armand
    13/06/18 a las 13:32