¿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
.
~[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.~
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 terminarreturn [1,2,3].indexOf(3) === -1;
~
es un binario no, invertirá cada bit del valor individualmente.[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-1
consta de solo 1, su complemento es0
, 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 conindexOf
.[[1,2],[3,4]].includes([3,4])
?Respuestas:
Los navegadores modernos tienen
Array#includes
, lo que hace exactamente eso y es ampliamente compatible con todos, excepto IE: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:
$.inArray(value, array, [fromIndex])
_.contains(array, value)
(también con alias como_.include
y_.includes
)dojo.indexOf(array, value, [fromIndex, findLast])
array.indexOf(value)
array.indexOf(value)
findValue(array, value)
array.indexOf(value)
Ext.Array.contains(array, value)
_.includes(array, value, [from])
(es_.contains
anterior a 4.0.0)R.includes(value, array)
Observe que algunos marcos implementan esto como una función, mientras que otros agregan la función al prototipo de matriz.
fuente
Array.include
un prototipo que devuelve un valor booleanoarray.indexOf(object) != -1
inArray
es un nombre terrible para una función que devuelve el índice del elemento, y-1
si no existe. Esperaría que se devuelva un booleano.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
while
ciclo 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:Por supuesto, también puede extender el prototipo de matriz:
Y ahora simplemente puede usar lo siguiente:
fuente
for (o in array)
lo que no debería hacerse al recorrer la matriz en general ...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:
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 )fuente
Presenta ECMAScript 7
Array.prototype.includes
.Se puede usar así:
También acepta un segundo argumento opcional
fromIndex
:A diferencia
indexOf
, que usa la comparación estricta de igualdad , seincludes
compara con el algoritmo de igualdad SameValueZero . Eso significa que puede detectar si una matriz incluye unNaN
:También a diferencia
indexOf
,includes
no omite los índices faltantes:Actualmente todavía es un borrador, pero se puede rellenar para que funcione en todos los navegadores.
fuente
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:
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
if
declaración ya que devuelve un valor booleano:* 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.comfuente
Arrow functions
en este ejemplo no está tan bien soportado. Para obtener más detalles, consulte aquí: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Digamos que has definido una matriz así:
A continuación se presentan tres formas de verificar si hay una
3
allí. Todos regresan ya seatrue
ofalse
.Método de matriz nativa (desde ES2016) ( tabla de compatibilidad )
Como método de matriz personalizado (pre ES2016)
Función simple
fuente
Aquí hay una implementación compatible con JavaScript 1.6 de
Array.indexOf
:fuente
[].indexOf
es una abreviatura deArray.prototype.indexOf
. Los programadores Javascript paranoicos-defensivos evitan extender prototipos nativos a toda costa.[].indexOf
creando una nueva matriz y luego accediendoindexOf
, mientrasArray.prototype.indexOf
solo accede al prototipo directamente?[].indexOf === Array.prototype.indexOf
(pruébalo en FireBug), pero a la inversa[].indexOf !== Array.indexOf
.Utilizar:
fuente
x ? true : false
Suele ser redundante. Es aquí.array.indexOf(search) >= 0
Ya es un booleano. Justoreturn array.indexOf(search) >= 0
.Ampliar el
Array
objeto JavaScript es una muy mala idea porque introduce nuevas propiedades (sus métodos personalizados) enfor-in
bucles 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.
fuente
Un trazador de líneas:
fuente
array.filter(e=>e==x).length > 0
es equivalentearray.some(e=>e==x)
perosome
es más eficientePensando fuera de la caja por un segundo, si está haciendo esta llamada muchas veces, es mucho más eficiente usar
una matriz asociativaun Mapa para hacer búsquedas usando una función hash.https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
fuente
Yo uso lo siguiente:
fuente
Array.prototype.some () se agregó al estándar ECMA-262 en la quinta edición
fuente
contains = (a, obj) => a.some((element) => element === obj))
Una esperanza bidireccional
indexOf
/lastIndexOf
alternativa más rápida2015
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
contains
funció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
while
sobrefor
, pero por una razón no específica terminé escribiendo la función con un bucle for. También se podría hacer con unwhile --
.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
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
contains
función para reflejar la salida indexOf & lastIndexOf (básicamente,true
conindex
yfalse
con-1
). Eso no debería dañarlo.La variante prototipo de matriz
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
while
variante:¿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
fuente
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
JSON
,Set
y sorprendentementefind
(K, N, O) son más lentas en todos los navegadoresincludes
(F) es rápido solo en Chromefor
(C, D) yindexOf
(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 eficientefor
(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
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.
Mostrar fragmento de código
Array pequeño - 10 elementos
Puedes realizar pruebas en tu máquina AQUÍ
Matriz grande - 1.000.000 elementos
Puedes realizar pruebas en tu máquina AQUÍ
fuente
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.
fuente
Devuelve el índice de matriz si se encuentra, o -1 si no se encuentra
fuente
Usamos este fragmento (funciona con objetos, matrices, cadenas):
Uso:
fuente
Si está comprobando repetidamente la existencia de un objeto en una matriz, tal vez debería investigar
contains(a, obj)
.fuente
Solución que funciona en todos los navegadores modernos:
Uso:
Solución IE6 +:
Uso:
¿Por qué usar
JSON.stringify
?Array.indexOf
yArray.includes
(así como la mayoría de las respuestas aquí) solo se comparan por referencia y no por valor.Prima
ES6 one-liner no optimizado:
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
contains
función con una optimización de rendimiento. Gracias a ti por señalarlo.fuente
includes
funció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.contains([{ a: 1, b: 2 }], { b: 2, a: 1 })
porque los objetos en cadena mantienen el orden de las propiedades.sort-keys
nota en la parte inferiorUse 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:
Mi recomendación:
Notas:
$ .inArray funciona bien para determinar si existe un valor escalar en una matriz de escalares ...
... 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:
fuente
ECMAScript 6 tiene una elegante propuesta de búsqueda.
Aquí está la documentación de MDN sobre eso.
La funcionalidad de búsqueda funciona así.
Puede usar esto en ECMAScript 5 y siguientes definiendo la función .
fuente
Si bien
array.indexOf(x)!=-1
es 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 hacertable[x]!==undefined
o===undefined
:Manifestación:
(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).
fuente
Se puede usar Set que tiene el método "has ()":
fuente
return proxy.has(obj)
es mucho más limpio que dos líneas con la declaración if-else aquífunction contains(arr, obj) { return new Set(arr).has(obj); }
Utilizar:
Manifestación
Para saber exactamente qué
tilde
~
hacer en este punto, consulte esta pregunta ¿Qué hace una tilde cuando precede a una expresión? .fuente
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:fuente
contains([{ a: 1, b: 2 }], { b: 2, a: 1 })
porque los objetos en cadena mantienen el orden de las propiedades.De ninguna manera el mejor, pero me estaba poniendo creativo y añadiendo al repertorio.
No use esto
fuente
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.
Array.prototype. incluye -> (devuelve verdadero o falso )
Array.prototype. find -> (toma la devolución de llamada, devuelve el primer valor / objeto que devuelve verdadero en CB).
Array.prototype. findIndex -> (toma la devolución de llamada, devuelve el índice del primer valor / objeto que devuelve verdadero en CB).
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.
fuente
Una solución simple para este requisito es usar
find()
Si tiene una variedad de objetos como a continuación,
Luego puede verificar si el objeto con su valor ya está presente o no
si los datos son nulos, entonces no hay administrador; de lo contrario, devolverá el objeto existente como se muestra a continuación.
Luego puede encontrar el índice de ese objeto en la matriz y reemplazar el objeto usando el código siguiente.
Obtendrá valor como a continuación
Espero que esto ayude a cualquiera.
fuente
fuente