Underscore: _.union no funciona con matrices de objetos

Creado en 2 oct. 2015  ·  32Comentarios  ·  Fuente: jashkenas/underscore

_.union siempre producirá duplicados cuando se pasen matrices de objetos.

por ejemplo, _.union( [ { a:1 } ], [ { a:1 } ]) devolverá [ { a:1 }, { a:1 } ]

Perversamente, la propia función isEqual del subrayado le dirá que los objetos en cuestión son iguales. ¿Quizás podríamos tener una bandera / opción que dicte la comparación de igualdad a usar, o la opción de pasar un comparador?

change

Comentario más útil

Este hilo me inspiró a agregar _.intersectionWith , _.differenceWith , _.unionWith y _.uniqWith para manejar la personalización de comparación en mi propio código.

var array = [ { 'a': 1, 'b': 2 }, { 'a': 1, 'b': 3 }, { 'a': 1, 'b': 2 } ];

_.uniqWith(array, _.isEqual);
// => [{ 'a': 1, 'b': 2 }, { 'a': 1, 'b': 3 }]

Todos 32 comentarios

Me sorprende que aún no acepte la función de comparación. : +1:

Vale la pena señalar que esto se aplica a todas las demás funciones de cálculo de matrices como diferencia, intersección, única, etc.

Sería bueno si el conjunto completo de funciones de matriz pudiera actualizarse para permitir el uso de un comparador de igualdad diferente para los objetos.

¿No sería más fácil si tuviéramos una opción que compare la igualdad basada en el valor del parámetro booleano que podría pasarse a la función _.union ()? Si es cierto, compararía automáticamente todos los objetos de esa matriz.

Por ejemplo, _.union([1, 2, 3, 10, [{a:1}, {a:1}]], true) , generaría [1,2,3,10, {a:1}]

@ amiral84 No. Eso no está relacionado. Si quieres ese comportamiento, escribe union con flatten.

@michaelficarra ¿ Entonces me

@ amiral84 Parece que sí. La solicitud de función se explica de forma completa y sucinta en el primer comentario.

el problema subyacente parece estar en _.uniq ya que _.union es simplemente una función de envoltura para único y aplanar.

_.union = restArgs(function(arrays) {
  return _.uniq(flatten(arrays, true, true));
});

Este hilo me inspiró a agregar _.intersectionWith , _.differenceWith , _.unionWith y _.uniqWith para manejar la personalización de comparación en mi propio código.

var array = [ { 'a': 1, 'b': 2 }, { 'a': 1, 'b': 3 }, { 'a': 1, 'b': 2 } ];

_.uniqWith(array, _.isEqual);
// => [{ 'a': 1, 'b': 2 }, { 'a': 1, 'b': 3 }]

o algo como _.isCollection para determinar si se trata de una colección. Si se trata de una colección, las comparaciones deben usar _.isEqual lugar de === lo que no sirve de nada en el caso de una colección.

@dperrymorrow

debería usar _.isEqual lugar de === que no sirve de nada en el caso de una colección.

El cambio dinámico parece una mala idea. JS usa === o SameValueZero comparaciones para muchas cosas. Si hay una necesidad de salirse de esas comparaciones, algo como _.uniqWith sería suficiente.

Gracias por esto @jdalton , las funciones _opWith que mencionas son absolutamente perfectas para lo que estoy tratando de lograr. ¿Alguna idea de cuándo estarán disponibles a través del lanzamiento?

@jdalton es un buen punto en las comparaciones, pero ¿no usaría normalmente una clave para único en una colección en lugar de forzar a Underscore a detectar toda la diferencia entre los objetos?

¿No resolvería lo siguiente la solicitud de @ wilhen01 _ (aunque más detallada de lo deseado) _

_.chain([{ a: 1 }]).union( [{a: 1}]).unique('a').value();
//=> [{a: 1}]

¿No resolvería lo siguiente la solicitud de @ wilhen01 (aunque más detallada de lo deseado)?

_.uniq ya lo admite.

bien, ese es mi punto, el código anterior funciona actualmente como se publicó.
¿No podría simplemente llamar a uniq / unique con una clave sobre el resultado de la unión?

@dperrymorrow Piense un poquito fuera de ese ejemplo y agregue otra propiedad .

ok, te entiendo, lo siento ... No estoy tratando de ser beligerante, solo quería entender totalmente el problema. Me encantaría enviar una solicitud de extracción en la función _.uniqWith .

No te preocupes, eso sería genial.

_.intersectionWith, _.differenceWith, _.unionWith y _.uniqWith

¿No sería una API más agradable simplemente permitir que la función de comparación se pase opcionalmente como el argumento final, en lugar de acuñar cuatro funciones nuevas?

@jashkenas

¿No sería una API más agradable simplemente permitir que la función de comparación se pase opcionalmente como el argumento final, en lugar de acuñar cuatro funciones nuevas?

Sí, se podría hacer, pero hay complicaciones porque métodos como _.uniq ya admiten el paso de un iteratee y están muy sobrecargados con soporte para indicadores de búsqueda binarios / ordenados y parámetros de contexto también. Esto significaría introducir arity sniffing, que se siente demasiado inteligente para esta situación. Esto también complicaría los futuros esfuerzos de modularización porque agrupa muchas funcionalidades opcionales en un solo punto cuando las implementaciones podrían simplificarse y dividirse en métodos separados.

Correcto, un problema de diseño totalmente desafortunado. Pero crear nuevas funciones solo para permitir un comparador tampoco parece la solución correcta.

bien, entonces, ¿los parámetros adicionales de la función de comparación son el camino a seguir aquí?
Si es así, puedo actualizar mi solicitud de extracción.

la única parte complicada que preveo es hacer que el análisis de parámetros sea un poco más complicado como

_.uniq = _.unique = function(array, isSorted, iteratee, context) {
  if (!_.isBoolean(isSorted)) {
    context = iteratee;
    iteratee = isSorted;
    isSorted = false;
  }
//...

Quizás agregue una verificación adicional para ver si está clasificado _.isFunction luego trátelo como el comparador.

@jashkenas

Pero crear nuevas funciones solo para permitir un comparador tampoco parece la solución correcta.

Puede ser la mejor opción para una mala situación. Recientemente, he tenido el gusto de dividir la funcionalidad sobrecargada y estoy bastante contento con el resultado. Aunque aumenta la superficie de la API, permite implementaciones más simples y agrupaciones de métodos con temas similares como maxBy , uniqBy , pickBy , o uniqWith , unionWith , zipWith , o sortedIndexBy , sortedIndexOf , sortedUniq . En el caso de uniq aunque todavía uso una función de base compartida en este momento.

han actualizado esta solicitud de extracción # 2368 gracias.

Soy: +1: por uniqBy o uniqWith . Estaría completamente en contra de sobrecargar uniq más (como se propone actualmente # 2368)

: +1: @megawac , uniqBy .

Fwiw lodash usará uniqBy como la forma dividida de _.uniq(array, iteratee) y _.uniqWith como la forma para permitir la personalización del comparador.

Sí, pensándolo bien uniqWith es un nombre mejor

¿Debo extraer la solicitud en Lodash con el método separado entonces?
Pensé que los dos proyectos se fusionaron, ¿me equivoco?

@dperrymorrow

¿Debo extraer la solicitud en Lodash con el método separado, entonces

No es necesario, ya están en la rama maestra de borde de lodash.

Pensé que los dos proyectos se fusionaron, ¿me equivoco?

Todavía no. Sin embargo, Lodash v4 prueba algunas de las ideas de la fusión.

@jdalton ¿Puede por favor elaborar un poco más sobre la implementación de _.uniqWith con otro iteratee?

@Pavnii
Seguro. Puede consultar lodash / npm / _baseUniq .
Si se pasa un comparator , usa arrayIncludesWith helper para hacer la verificación en lugar de arrayIncludes (el subrayado contains ).

@jdalton Eso me ayuda.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

jdalton picture jdalton  ·  6Comentarios

githublyp picture githublyp  ·  3Comentarios

acl0056 picture acl0056  ·  5Comentarios

afranioce picture afranioce  ·  8Comentarios

arieljake picture arieljake  ·  4Comentarios