¿Cuál es el código más simple y sin biblioteca para implementar intersecciones de matriz en javascript? Quiero escribir
intersection([1,2,3], [2,3,4,5])
y obten
[2, 3]
¿Cuál es el código más simple y sin biblioteca para implementar intersecciones de matriz en javascript? Quiero escribir
intersection([1,2,3], [2,3,4,5])
y obten
[2, 3]
break
aSimple js loops
aumenta las operaciones por segundo a ~ 10MRespuestas:
Use una combinación de
Array.prototype.filter
yArray.prototype.indexOf
:O como vrugtehagel sugirió en los comentarios, puede usar el
Array.prototype.includes
código más reciente para un código aún más simple:Para navegadores antiguos:
fuente
intersection([1,2,1,1,3], [1])
vuelve[1, 1, 1]
. ¿No debería volver solo[1]
?array2.indexOf(n) != -1
uno, también puede escribirarray2.includes(n)
para un código aún más simple.Destructivo parece más simple, especialmente si podemos suponer que la entrada está ordenada:
No destructivo tiene que ser un cabello más complicado, ya que tenemos que rastrear índices:
fuente
intersect_safe
:length
es una propiedad en Matrices, no un método. Hay una variable sin demorai
enresult.push(a[i]);
. Finalmente, esto simplemente no funciona en el caso general: dos objetos donde ninguno es mayor que el otro según el>
operador no son necesariamente iguales.intersect_safe( [ {} ], [ {} ] )
, por ejemplo, le dará (una vez que se hayan corregido los errores mencionados anteriormente) una matriz con un elemento, que es claramente incorrecto..slice(0)
para crear un clon de la matrizintersect_safe
, en lugar de rastrear índices.Si su entorno es compatible con ECMAScript 6 Set , una forma simple y supuestamente eficiente (ver enlace de especificación):
Más corto, pero menos legible (también sin crear la intersección adicional
Set
):Evitar un nuevo
Set
deb
cada vez:Tenga en cuenta que cuando use conjuntos solo obtendrá valores distintos, por lo tanto se
new Set[1,2,3,3].size
evalúa como3
.fuente
[...setA]
sintaxis? ¿Algún tipo especial de operación de JavaScript?x => new Set(b).has(x)
convierte esa función de flechab
en un conjunto cada vez que se ejecuta? Probablemente debería guardar ese conjunto en una variable.Usando Underscore.js o lodash.js
fuente
Mi contribución en términos de ES6. En general, encuentra la intersección de una matriz con un número indefinido de matrices proporcionadas como argumentos.
fuente
[[0,1,2,3,4,5,6,7,8,9],[0,2,4,6,8],[4,5,6,7],[4,6]]
y luego se aplica.reduce()
.[0,1,2,3,4,5,6,7,8,9].filter( e => [0,2,4,6,8].includes(e)
Se realiza la primera operación y el resultado se convierte en nuevop
y sec
convierte[4,5,6,7]
en el siguiente turno y continúa así hasta que noc
quede más.prototype
innecesariamente.Recomiendo una solución sucinta que supera a otras implementaciones en entradas grandes. Si el rendimiento en entradas pequeñas es importante, verifique las alternativas a continuación.
Alternativas y comparación de rendimiento:
Consulte el siguiente fragmento para ver implementaciones alternativas y consulte https://jsperf.com/array-intersection-comparison para ver las comparaciones de rendimiento.
Mostrar fragmento de código
Resultados en Firefox 53:
Ops / seg en matrices grandes (10,000 elementos):
Ops / seg en matrices pequeñas (100 elementos):
fuente
intersect([1,2,2,3], [2,3,4,5])
vuelve[2, 2, 3]
.a.filter(b.includes)
. Debería ejecutarse considerablemente más rápido (igual que la actualización de su función).¿Qué tal si solo usamos matrices asociativas?
editar:
fuente
Object.prototype
.d[b[i]] = true;
lugar ded[b[j]] = true;
(i
noj
). Pero editar requiere 6 caracteres.Algo como esto, aunque no se ha probado bien.
PD: El algoritmo solo está destinado a Números y Cadenas normales, la intersección de matrices de objetos arbitrarios puede no funcionar.
fuente
El rendimiento de la implementación de @ atk para matrices ordenadas de primitivas se puede mejorar utilizando .pop en lugar de .shift.
Creé un punto de referencia usando jsPerf: http://bit.ly/P9FrZK . Es aproximadamente tres veces más rápido usar .pop.
fuente
a[aLast] > b[bLast]
cona[aLast].localeCompare(b[bLast]) > 0
(y lo mismo con elelse if
siguiente), esto funcionará en cadenas..pop
es O (1) y.shift()
es O (n)Usando jQuery :
fuente
c = $(b).filter(a);
, pero no recomendaría confiar en jQuery para este tipo de manipulación de matriz ya que la documentación solo menciona que funciona para elementos.Para las matrices que contienen solo cadenas o números, puede hacer algo con la clasificación, según algunas de las otras respuestas. Para el caso general de matrices de objetos arbitrarios, no creo que puedas evitar hacerlo a la larga. Lo siguiente le dará la intersección de cualquier número de matrices proporcionadas como parámetros para
arrayIntersection
:fuente
firstArr
ofirstArray
no actualicé todas las referencias. Fijo.Es bastante corto usando ES2015 y Sets. Acepta valores de tipo matriz como una cadena y elimina duplicados.
fuente
Se puede usar un
Set
comothisArg
deArray#filter
y tomarSet#has
como devolución de llamada.fuente
Un pequeño ajuste al más pequeño aquí (la solución filter / indexOf ), es decir, crear un índice de los valores en una de las matrices usando un objeto JavaScript, lo reducirá de O (N * M) a "probablemente" tiempo lineal. Source1 source2
Esta no es la solución más simple (es más código que filter + indexOf ), ni es la más rápida (probablemente más lenta por un factor constante que intersect_safe () ), pero parece un buen balance. Es del lado muy simple, a la vez que proporciona un buen rendimiento, y no requiere entradas ordenadas previamente.
fuente
Otro enfoque indexado capaz de procesar cualquier cantidad de matrices a la vez:
Funciona solo para valores que pueden evaluarse como cadenas y debe pasarlos como una matriz como:
... pero acepta objetos de forma transparente como parámetro o como cualquiera de los elementos que se van a intersectar (siempre devuelve una matriz de valores comunes). Ejemplos:
EDITAR: Acabo de notar que esto es, en cierto modo, un poco defectuoso.
Es decir: lo codifiqué pensando que las matrices de entrada por sí mismas no pueden contener repeticiones (como el ejemplo provisto no lo hace).
Pero si las matrices de entrada contienen repeticiones, eso produciría resultados incorrectos. Ejemplo (usando la implementación a continuación):
Afortunadamente, esto es fácil de solucionar simplemente agregando indexación de segundo nivel. Es decir:
Cambio:
por:
...y:
por:
Ejemplo completo:
fuente
var v =
línea agregueif (typeof v == 'function') continue;
y omitirá agregar funciones a los resultados. ¡Gracias!if (typeof v == 'function')
, entonces podemos usar su stringificación (v.toString()
) como clave para el índice. Pero, debemos hacer algo para preservarlo intacto. forma más fácil de hacerlo es simplemente asignar la función original como valor en lugar de una simple verdadero valor booleano Pero, en ese caso, la última deindexaton debe también alteró para detectar esta condición y restaurar el valor de la derecha (la función)..Puede usar (para todos los navegadores excepto IE):
o para IE:
fuente
fuente
Con algunas restricciones en sus datos, puede hacerlo en forma lineal. tiempo !
Para enteros positivos : utilice una matriz que asigne los valores a un booleano "visto / no visto".
Existe una técnica similar para los objetos : tome una clave ficticia, configúrela como "verdadera" para cada elemento de la matriz1, luego busque esta clave en los elementos de la matriz2. Limpia cuando hayas terminado.
Por supuesto, debes asegurarte de que la clave no apareció antes, de lo contrario estarás destruyendo tus datos ...
fuente
Contribuiré con lo que me ha funcionado mejor:
fuente
"indexOf" para IE 9.0, Chrome, Firefox, Opera,
fuente
fuente
Un enfoque funcional con ES2015
Un enfoque funcional debe considerar el uso de funciones puras sin efectos secundarios, cada uno de los cuales solo tiene que ver con un solo trabajo.
Estas restricciones mejoran la componibilidad y la reutilización de las funciones involucradas.
Tenga en cuenta que el nativo
Set
se utiliza el tipo , que tiene un rendimiento de búsqueda ventajoso.Evitar duplicados
Obviamente, los elementos que ocurren repetidamente del primero
Array
se conservan, mientras que el segundoArray
se desduplica. Este puede ser o no el comportamiento deseado. Si necesita un resultado único, simplemente apliquededupe
el primer argumento:Calcule la intersección de cualquier número de
Array
sSi desea calcular la intersección de un número arbitrario de
Array
s simplemente compongaintersect
confoldl
. Aquí hay una función de conveniencia:fuente
(expr ? true : false)
es redundante. Úselo soloexpr
si no se necesitan booleanos reales, solo verdadero / falso.Por simplicidad:
Beneficios:
Inconvenientes:
No querrás usar esto para el motor 3D o el trabajo del kernel, pero si tienes problemas para que esto se ejecute en una aplicación basada en eventos, tu diseño tiene problemas más grandes.
fuente
.reduce
para construir un mapa y.filter
encontrar la intersección.delete
dentro de.filter
nos permite tratar la segunda matriz como si fuera un conjunto único.Me parece bastante fácil razonar sobre este enfoque. Se realiza en tiempo constante.
fuente
Este es probablemente el más simple, además de list1.filter (n => list2.includes (n))
fuente
Si necesita que maneje la intersección de múltiples matrices:
fuente
Estilo ES6 de forma sencilla.
Ejemplo:
fuente
He escrito una función de intersección que incluso puede detectar la intersección de una matriz de objetos en función de la propiedad particular de esos objetos.
Por ejemplo,
y queremos intersección basada en la
id
propiedad, entonces la salida debería ser:Como tal, la función para el mismo (nota: código ES6) es:
y puedes llamar a la función como:
También tenga en cuenta: esta función encuentra la intersección considerando que la primera matriz es la matriz primaria y, por lo tanto, el resultado de la intersección será el de la matriz primaria.
fuente
Piense que esto será más rápido con el tiempo O (array1 + array2) suponiendo que map.has () es ~ O (1). Corríjame si está equivocado.
fuente
Aquí está la implementación de underscore.js :
Fuente: http://underscorejs.org/docs/underscore.html#section-62
fuente