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

4000

¿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 en que sé hacerlo:

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

¿Hay una manera mejor y más concisa de lograr esto?

Esto está muy relacionado con la pregunta de desbordamiento de pila. ¿La mejor manera de encontrar un elemento en una matriz de JavaScript? que aborda la búsqueda de objetos en una matriz usando indexOf.

puntilla
fuente
49
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 (aparte de guardar previamente una longitud en una variable) mientras usa indexOf (como en $ .inArray) es mucho más lento
Jörn Berkefeld
17
muchos han respondido que el Array # indexOf es su mejor opción aquí. Pero si desea algo que se pueda convertir correctamente a Boolean, 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.
lordvlad
8
~no es lo que quiere usar para convertir a un booleano, para eso lo necesita !. Pero en este caso, desea verificar la igualdad con -1, por lo que la función podría terminar return [1,2,3].indexOf(3) === -1; ~es un binario no, invertirá cada bit del valor individualmente.
mcfedr
14
@Iordvlad en [1,2,3].indexOf(4)realidad devolverá -1 . Como señaló @mcfedr, ~es el operador bit-NOT , ver ES5 11.4.8. La cosa es que, dado que la representación binaria de -1consta de solo 1, 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
55
El título es engañoso. ¿Dónde está el [[1,2],[3,4]].includes([3,4])?
mplungjan

Respuestas:

4381

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

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

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


Muchos marcos también ofrecen métodos similares:

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

codeape
fuente
42
MooTools también tiene Array.contains que devuelve un valor booleano, que aquí parece ser la pregunta real.
Ryan Florence
22
también tiene Array.includeun prototipo que devuelve un valor booleano
user102008
46
Si está utilizando un buen navegador, puede usararray.indexOf(object) != -1
Sam Soffes el
13
Además, no use indexOf solo como condición, porque el primer elemento devolverá 0 y será evaluado como falso
más-
241
inArrayes un nombre terrible para una función que devuelve el índice del elemento, y -1si no existe. Esperaría que se devuelva un booleano.
Tim
434

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 los navegadores de la época. Puede que no sea relevante para los contextos modernos de ejecución de JS. Si necesita una solución fácil, busque otras respuestas. Si necesita el mejor rendimiento, hágalo una referencia en los entornos de ejecución relevantes.

Como otros han dicho, la iteración a través de la matriz es probablemente la mejor manera, pero se ha demostrado que un whileciclo decreciente es la forma más rápida de iterar en JavaScript. Por lo tanto, es posible que desee volver a escribir 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 de matriz:

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
Damir Zekić
fuente
22
"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
2
@Damir: estoy de acuerdo. Quizás cambie la muestra para usar indexOf si está disponible, solo para que las personas que copien y peguen este código a ciegas obtendrán el mejor rendimiento posible.
orip
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 ...
Damir Zekić
1
La mejor manera de hacerlo es verificar si [1, 2, 3] .indexOf (1)> -1
Devin G Rhode
207

indexOf tal vez, pero es una "extensión de JavaScript para el estándar ECMA-262; como tal, puede no estar 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 algú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 en Google (por ejemplo, esta )

cic
fuente
en realidad, hay un ejemplo de la implementación de la extensión indexOf para navegadores que no lo admiten en la página developer.mozilla.org a la que se vinculó.
Lloyd Cotten
en realidad, si agrega indexof al prototipo de Array para navegadores que no lo admiten (es decir, IE7), también intentarán recorrer esta función cuando recorran los elementos de la matriz. asqueroso.
CpILL
¿Es aplicable verificar el Objeto? no creo que funcione en el caso del Objeto
Himesh Aadeshara
169

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 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 un NaN:

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

También a diferencia indexOf, 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.

Oriol
fuente
3
No es compatible con IE y Microsfot Edge (2015) ( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… )
Adriano Resende
1
También es relevante, la tabla de compatibilidad ES7 (parece que Chrome la admite ahora)
styfle
¿Es aplicable verificar el Objeto? no creo que funcione en el caso del Objeto
Himesh Aadeshara
128

Las respuestas principales suponen tipos primitivos, pero si desea averiguar si una matriz contiene un objeto con algún rasgo, Array.prototype.some () es una solución muy 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 cancela una vez que se encuentra el elemento, por lo que se ahorran ciclos de iteración innecesarios.

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

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

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

Miguel
fuente
1
A partir de hoy, septiembre de 2018, Array.prototype.some () es totalmente compatible: tabla de soporte
caniuse.com
1
Trabajando en Nodo> = 8.10 para AWS Node.js Lambda, así que esto es genial. ¡Solución muy limpia y simple! 👍🏻
Jordania
1
@jamess Puede estar bien soportado, pero recuerde que Arrow functionsen este ejemplo no está tan bien soportado. Para obtener más detalles, consulte aquí: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Kamil Witkowski el
¿Algún cortocircuito? ¿O itera toda la matriz incluso si se encuentra un valor?
Douglas Gaskell el
@DouglasGaskell aborta la iteración una vez encontrada (mencionada en la respuesta)
Michael
112

Digamos que has definido una matriz así:

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

A continuación se presentan tres formas de verificar si hay una 3allí. Todos regresan ya sea trueo false.

Método de matriz nativa (desde ES2016) ( tabla de compatibilidad )

array.includes(3) // true

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

Función simple

const includes = (a, v) => a.indexOf(v) !== -1
includes(array, 3) // true
william malo
fuente
Devuelve verdadero si "b" está en la matriz "a" ... No sé cómo explicarlo ...
william malo
44
Esta parte no entiendo "!! ~". Y creo que esto no funcionará en IE8 porque IE8 no admite indexOf () en el objeto Array.
svlada
6262
"~" es un operador que coloca, invierte y resta 1 de un número. indexOf devuelve -1 si falla, por lo que "~" convierte -1 en "0". utilizando "!!" convierte los números en boleanos (!! 0 === falso)
william malo
1
Genial, pero en serio por simplicidad y no solo a.indexOf (b)> - 1, ya que "> -1" .length === "!! ~" .length
super
2
Yo diría que la falta de conocimiento sobre los efectos de los operadores booleanos no es profesional. Pero estoy de acuerdo con el valor del código legible, ciertamente lo envolvería en una función claramente etiquetada. Y eso es exactamente lo que hacen los principales frameworks JS.
okdewit
79

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;
        };
}
Már Örlygsson
fuente
Esto se ve genial, pero un poco confundido: * ¿No son equivalentes las pruebas en las líneas 1 y 3? * ¿No sería mejor probar el prototipo y agregar la función a Array.prototype si es necesario?
Avi Flax
10
No son equivalentes. [].indexOfes una abreviatura de Array.prototype.indexOf. Los programadores Javascript paranoicos-defensivos evitan extender prototipos nativos a toda costa.
Már Örlygsson
1
¿No está [].indexOfcreando una nueva matriz y luego accediendo indexOf, mientras Array.prototype.indexOfsolo accede al prototipo directamente?
alex
3
@alex sí [].indexOf === Array.prototype.indexOf(pruébalo en FireBug), pero a la inversa [].indexOf !== Array.indexOf.
Már Örlygsson
57

Utilizar:

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

// Usage
if(isInArray(my_array, "my_value"))
{
    //...
}
Matías Cánepa
fuente
25
x ? true : falseSuele ser redundante. Es aquí.
Ry-
@minitech ¿Por qué dices que es redundante?
Matías Cánepa
8
array.indexOf(search) >= 0Ya es un booleano. Justo return array.indexOf(search) >= 0.
Ry-
@minitech bien gracias! En realidad no sabía que tal construcción podría ser devuelta. TIL algo nuevo.
Matías Cánepa
Literalmente, cualquier construcción en JavaScript se puede devolver
BT
49

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

Peter Mortensen
fuente
22
Estoy en desacuerdo. Los bucles for-in no deben usarse para matrices precisamente por este motivo. El uso de bucles for-in se interrumpirá cuando se use una de las bibliotecas js populares
Tomás
¿Se consideraría esto un parche de mono? jajaja A algunas personas les gusta eso.
cbmeeks
33

Un trazador de líneas:

function contains(arr, x) {
    return arr.filter(function(elem) { return elem == x }).length > 0;
}
AlonL
fuente
8
array.filter(e=>e==x).length > 0es equivalente array.some(e=>e==x)pero somees más eficiente
Apolo
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
Eduardo Cuomo
fuente
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

dansalmo
fuente
si usa es6 de lo que puede acortarse comocontains = (a, obj) => a.some((element) => element === obj))
diEcho
Incluso IE9 tiene soporte para Array.prototype.some () a partir de ECMAScript 5 .
Suncat2000
19

Una esperanza bidireccional indexOf/ lastIndexOfalternativa más rápida

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 slow indexOf / lastIndexOf.

Ya se ha encontrado una forma eficaz, mirando las respuestas principales. De esos 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 whilesobre for, pero por una razón no específica terminé escribiendo la función con un bucle for. También se podría hacer con un while --.

Tenía curiosidad si la iteración era mucho más lenta si revisaba 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 grandes matrices y el resultado podría estar en todas partes, esta podría ser una solución sólida para acelerar las cosas.

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 rendimiento

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 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, 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 realiza tres comprobaciones por iteración, pero esto solo es posible con un cálculo más largo que causa la desaceleración del código.

http://jsperf.com/bidirectionalindexof/2

coco
fuente
18

Actuación

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 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 la forma de caché de la CPU funciona .
  • También ejecuté la prueba de matriz grande 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 centro de la matriz.

Array pequeño - 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í

Kamil Kiełczewski
fuente
16

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

Andru Luvisi
fuente
16
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 matriz si se encuentra, o -1 si no se encuentra

LmC
fuente
16

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
dr.dimitru
fuente
15

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 eliminar + operación de inserción ordenada y
  3. Use una búsqueda binaria en su contains(a, obj).
Ztyx
fuente
2
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.
joeytwiddle
13

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é usar JSON.stringify?

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

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

Prima

ES6 one-liner no optimizado:

[{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 a ti por señalarlo.

Igor Barbashin
fuente
Este fragmento de código en particular puede funcionar en IE6 (no lo he probado), pero IE no admitió ES5 hasta IE9.
Mark Reed
Por razones de rendimiento, debe evitar encadenar. Al menos debe evitar JSON.stringify el "obj" en cada bucle porque es costoso y ralentizará su aplicación. Por lo tanto, debe capturarlo antes del ciclo for en una variable temporal
inicia el
1
@inicio buen punto. Actualizó la includesfunción con su sugerencia. Ejecuté jsperf con mi función. Es aproximadamente 5 veces más lento que lo que incluye Lodash. Aunque lodash no se puede comparar por su 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 efectiva y no increíblemente compleja de hacerlo.
Igor Barbashin
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.
Heretic Monkey
1
@ HereticMonkey, cierto. Es por eso que agregué la sort-keysnota en la parte inferior
Igor Barbashin el
12

Use alguna función de lodash .

Es conciso, preciso y tiene un gran soporte multiplataforma.

La respuesta aceptada ni siquiera cumple 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 manera eficiente de determinar si un objeto está contenido en una matriz.

Para manejar tanto escalares como objetos, puede hacer esto:

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

ECMAScript 6 tiene una elegante propuesta de búsqueda.

El método find ejecuta la función de devolución de llamada una vez para cada elemento presente en la matriz hasta que encuentra una donde la devolución de llamada devuelve un valor verdadero. Si se encuentra dicho elemento, buscar inmediatamente devuelve el valor de ese elemento. De lo contrario, encuentra devoluciones indefinidas. la devolución de llamada se invoca solo para índices de la matriz que tienen valores asignados; no se invoca para índices que se han eliminado o a los que nunca se les han asignado valores.

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;
    }
  });
}
Pradeep Mahdevu
fuente
9

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 va a cambiar, puede convertir su matriz en una tabla hash, luego hacer 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, si bien 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 adelante. JavaScript no tiene suficientes enlaces para le permite mantener este estado, a diferencia de Python, por ejemplo).

ninjagecko
fuente
9

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

rlib
fuente
55
Creo que return proxy.has(obj)es mucho más limpio que dos líneas con la declaración if-else aquí
Maciej Bukowski
function contains(arr, obj) { return new Set(arr).has(obj); }
Gordon Bean
8

Utilizar:

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

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

Manifestación

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

Mina Gabriel
fuente
55
Esto ya se publicó hace un año y medio, no es necesario repetirlo.
Shadow Wizard es Ear For You el
3
En realidad, no ha sido publicado. No como una respuesta, sino como un comentario a una respuesta, y aun así no es claro y conciso. Gracias por publicarlo, Mina Gabriel.
T.CK
6

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

Hay muchas maneras 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;
}
Alireza
fuente
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.
Heretic Monkey
5

De ninguna manera el mejor, pero me estaba poniendo creativo y añadiendo 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'));

sqram
fuente
¿Qué deberías usar si no es esto?
bryc
@bryc tal vez la solución aceptada, u otra solución desde aquí. Si no le interesa mucho el rendimiento, puede usar esto
sqram
5

Sorprendido de 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 él.

Array.prototype. indexOf -> (devuelve índice o -1 ) se usa generalmente para encontrar el índice del elemento en la matriz. Esto también se puede usar para buscar objetos, pero solo funciona si está pasando referencias 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. find -> (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 -> (toma la 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 toma una devolución de llamada, podemos recuperar cualquier objeto (incluso si no tenemos la referencia) de la matriz configurando creativamente la verdadera condición.

Sumeria
fuente
5

Una solución simple para este requisito es usar 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 código siguiente.

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

Obtendrá 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.

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

Sanjay Magar
fuente