¿Hay alguna manera de devolver la diferencia entre dos matrices en JavaScript?
Por ejemplo:
var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];
// need ["c", "d"]
javascript
arrays
array-difference
John Adawan
fuente
fuente
O(a1.length x log(a2.length))
: ¿es posible este rendimiento en JavaScript?Respuestas:
Supongo que está comparando una matriz normal. De lo contrario, debe cambiar el bucle for por un bucle for .. in .
Una solución mejor, si no le importa la compatibilidad con versiones anteriores, es usar el filtro. Pero aún así, esta solución funciona.
fuente
var a1 = ['a', 'b'];
yvar a2 = ['a', 'b', 'c', 'd', 'b'];
, devolverá una respuesta incorrecta , es decir, en['c', 'd', 'b']
lugar de['c', 'd']
.function diff2(a, b) { var i, la = a.length, lb = b.length, res = []; if (!la) return b; else if (!lb) return a; for (i = 0; i < la; i++) { if (b.indexOf(a[i]) === -1) res.push(a[i]); } for (i = 0; i < lb; i++) { if (a.indexOf(b[i]) === -1) res.push(b[i]); } return res; }
Hay una mejor manera de usar ES7:
Intersección
Porque
[1,2,3] [2,3]
rendirá[2,3]
. Por otro lado, for[1,2,3] [2,3,5]
devolverá lo mismo.Diferencia
Porque
[1,2,3] [2,3]
rendirá[1]
. Por otro lado, for[1,2,3] [2,3,5]
devolverá lo mismo.Para una diferencia simétrica , puedes hacer:
De esta manera, obtendrá una matriz que contiene todos los elementos de arr1 que no están en arr2 y viceversa.
Como @Joshaven Potter señaló en su respuesta, puede agregar esto a Array.prototype para que pueda usarse así:
fuente
< 0
lugar de== -1
Array
diferencia se llama asíset operation
, porque la búsqueda de propiedades es el trabajo propio deSet
s, que son órdenes de magnitud más rápido queindexOf
/includes
. En pocas palabras, su solución es muy ineficiente y bastante lenta.Set
, los valores tienen que ser únicos, ¿no?[1,2,3] [2,3,5]
dado que los números son únicos, pero si lo dijera[1,1,2,3] [1,2,3,5]
y esperara,[1]
no podría usarloSet
. Sin embargo, su solución tampoco funcionaría: - / Terminé creando esta función porque no pude encontrar una manera satisfactoria de hacerlo de manera más sucinta. Si tienes alguna idea sobre cómo hacerlo, ¡me encantaría saberlo!Array.includes()
es la función ES7 en lugar de ES6? (1) (2) - y para continuar, con ES6 podría usar ,Array.some()
por ejemplolet intersection = aArray.filter(a => bArray.some(b => a === b))
, ¿no?Mostrar fragmento de código
Nota indexOf y filter no están disponibles en ie antes de ie9.
fuente
[1,2,3].diff([3,4,5])
volverá en[1,2]
lugar de[1,2,4,5]
hacerlo, por lo que no resuelve el problema en la pregunta original, algo a tener en cuenta.Esta es, con mucho, la forma más fácil de obtener exactamente el resultado que está buscando, utilizando jQuery:
diff
ahora contiene lo que estaba enold_array
eso no está ennew_array
fuente
{a: 1} != {a: 1}
) ( prueba ).not
con una matriz, jQuery usa su utilidad incorporada.grep()
que es específicamente para filtrar matrices. No puedo ver esto cambiando.El método de diferencia en Underscore (o su reemplazo directo , Lo-Dash ) también puede hacer esto:
Al igual que con cualquier función de subrayado, también puede usarla en un estilo más orientado a objetos:
fuente
JavaScript simple
Hay dos posibles interpretaciones para la "diferencia". Te dejaré elegir cuál quieres. Digamos que tienes:
Si desea obtener
['a']
, use esta función:Si desea obtener
['a', 'c']
(todos los elementos contenidos en unoa1
oa2
, pero no en ambos, la llamada diferencia simétrica ), use esta función:Lodash / subrayado
Si está usando lodash, puede usar
_.difference(a1, a2)
(caso 1 arriba) o_.xor(a1, a2)
(caso 2).Si está utilizando Underscore.js, puede usar el
_.difference(a1, a2)
función para el caso 1.Conjunto ES6, para matrices muy grandes
El código anterior funciona en todos los navegadores. Sin embargo, para matrices grandes de más de aproximadamente 10,000 artículos, se vuelve bastante lento, porque tiene una complejidad O (n²). En muchos navegadores modernos, podemos aprovechar el
Set
objeto ES6 para acelerar las cosas. Lodash usa automáticamenteSet
cuando está disponible. Si no está usando lodash, use la siguiente implementación, inspirada en la publicación de blog de Axel Rauschmayer :Notas
El comportamiento de todos los ejemplos puede ser sorprendente o no obvio si le interesan los conjuntos -0, +0, NaN o dispersos. (Para la mayoría de los usos, esto no importa).
fuente
Para obtener la diferencia simétrica , debe comparar las matrices de ambas maneras (o de todas las formas en caso de múltiples matrices)
ES7 (ECMAScript 2016)
ES6 (ECMAScript 2015)
ES5 (ECMAScript 5.1)
Ejemplo:
Diferencia entre matrices de objetos
Ejemplo:
fuente
Un enfoque más limpio en ES6 es la siguiente solución.
Diferencia
Intersección
Unión disyuntiva (diferencia simétrica)
fuente
a1 = ['a', 'b', 'e']
: e no se extraerá.Podrías usar un Set en este caso. Está optimizado para este tipo de operación (unión, intersección, diferencia).
Asegúrese de que se aplique a su caso, una vez que no permita duplicados.
fuente
Set
función sin tener que conseguir todo lo demás ...Combine ambas matrices, los valores únicos aparecerán solo una vez, por lo que indexOf () será el mismo que lastIndexOf ().
fuente
para restar una matriz de otra, simplemente use el fragmento a continuación:
Devolverá ['1,' 2 ',' 6 '] que son elementos de la primera matriz que no existen en la segunda.
Por lo tanto, de acuerdo con su ejemplo de problema, el siguiente código es la solución exacta:
fuente
Con la llegada de ES6 con sets y operador splat (al momento de funcionar solo en Firefox, consulte la tabla de compatibilidad ), puede escribir el siguiente delineador:
que dará lugar a
[ "c", "d" ]
.fuente
b.filter(x => !a.indexOf(x)))
O(n + m)
su solución esO(n * m)
donde nym son longitudes de matrices. Tome listas largas y mi solución se ejecutará en segundos, mientras que la suya tomará horas.a.filter(x => !b1.has(x))
es más simple Y tenga en cuenta la especificación sólo requiere la complejidad de sern * f(m) + m
conf(m)
sublinear en promedio. Es mejor quen * m
, pero no necesariamenten + m
.var difference = [...new Set([...a].filter(x => !b1.has(x)))];
¿ Por qué estás creando una matriz 'a' duplicada? ¿Por qué está convirtiendo el resultado del filtro en un conjunto y luego nuevamente en una matriz? ¿No es esto equivalente avar difference = a.filter(x => !b1.has(x));
Enfoque funcional con ES2015
Calcular
difference
entre dos matrices es una de lasSet
operaciones. El término ya indica que seSet
debe usar el tipo nativo para aumentar la velocidad de búsqueda. De todos modos, hay tres permutaciones cuando calcula la diferencia entre dos conjuntos:Aquí hay una solución funcional que refleja estas permutaciones.
Izquierda
difference
:Derecha
difference
:differencer
es trivial Es solodifferencel
con argumentos invertidos. Puede escribir una función por conveniencia:const differencer = flip(differencel)
. ¡Eso es todo!Simétrico
difference
:Ahora que tenemos el izquierdo y el derecho, implementar la simétrica también
difference
es trivial:Supongo que este ejemplo es un buen punto de partida para obtener una impresión de lo que significa la programación funcional:
Programación con bloques de construcción que se pueden conectar de muchas maneras diferentes.
fuente
Una solución usando
indexOf()
estará bien para matrices pequeñas pero a medida que crecen en longitud, el rendimiento del algoritmo se acercaO(n^2)
. Aquí hay una solución que funcionará mejor para matrices muy grandes mediante el uso de objetos como matrices asociativas para almacenar las entradas de la matriz como claves; también elimina entradas duplicadas automáticamente, pero solo funciona con valores de cadena (o valores que se pueden almacenar de forma segura como cadenas):fuente
La respuesta anterior de Joshaven Potter es genial. Pero devuelve elementos en la matriz B que no están en la matriz C, pero no al revés. Por ejemplo, si
var a=[1,2,3,4,5,6].diff( [3,4,5,7]);
entonces generará: ==>[1,2,6]
, pero no[1,2,6,7]
, que es la diferencia real entre los dos. Todavía puede usar el código de Potter anterior, pero simplemente vuelva a hacer la comparación una vez al revés también:Esto debería generar:
[ 1, 2, 6, 7 ]
fuente
Otra forma de resolver el problema.
Además, puede usar la sintaxis de la función de flecha:
fuente
fuente
difference
como función en una versión futura y esta función tiene una firma de función diferente a la suya, romperá su código o las bibliotecas extranjeras que usen esta función.Solución muy simple con la función de filtro de JavaScript:
fuente
Qué tal esto:
Entonces, de esta manera, puede hacer
array1.diff(array2)
para obtener su diferencia (Sin embargo, la complejidad de tiempo horrible para el algoritmo - O (array1.length x array2.length) creo)fuente
Usando http://phrogz.net/JS/ArraySetMath.js puedes:
fuente
esto funciona para mi
fuente
filter
)fn
Parámetro de devolución de llamada opcional que le permite especificar cómo comparar elementos de la matrizfuente
length
valores. Ya es una propiedad simple. jsperf.com/array-length-cachingEsto está funcionando: básicamente combina las dos matrices, busca los duplicados y empuja lo que no está duplicado en una nueva matriz, que es la diferencia.
fuente
// enfoque es6
fuente
Complejidad simétrica y lineal . Requiere ES6.
fuente
Otra respuesta más, pero parece que nadie mencionó jsperf donde comparan varios algoritmos y soporte tecnológico: https://jsperf.com/array-difference-javascript parece que usar el filtro obtiene los mejores resultados. Gracias
fuente
Solo pensando ... en aras de un desafío ;-) ¿funcionaría esto ... (para matrices básicas de cadenas, números, etc.) sin matrices anidadas
Tenga en cuenta que la clasificación probablemente no será como se indicó anteriormente ... pero si lo desea, llame a .sort () en la matriz para ordenarlo.
fuente
Quería una función similar que tomara una matriz antigua y una matriz nueva y me diera una matriz de elementos agregados y una matriz de elementos eliminados, y quería que fuera eficiente (¡así que no contiene!).
Puedes jugar con mi solución propuesta aquí: http://jsbin.com/osewu3/12 .
¿Alguien puede ver algún problema / mejora de ese algoritmo? ¡Gracias!
Listado de código:
fuente
Estaba buscando una respuesta simple que no implicara el uso de diferentes bibliotecas, y se me ocurrió una propia que no creo que se haya mencionado aquí. No sé qué tan eficiente es ni nada, pero funciona;
Para mi código, también necesito sacar duplicados, pero supongo que no siempre es preferible.
Supongo que el principal inconveniente es que potencialmente está comparando muchas opciones que ya han sido rechazadas.
fuente
littlebit arregla la mejor respuesta
Esto tendrá en cuenta el tipo de elemento actual. b / c cuando hacemos un [a1 [i]] convierte un valor a cadena desde su valor original, por lo que perdimos el valor real.
fuente