El nuevo ES 6 (Harmony) presenta un nuevo objeto Set . El algoritmo de identidad utilizado por Set es similar al ===
operador y, por lo tanto, no es muy adecuado para comparar objetos:
var set = new Set();
set.add({a:1});
set.add({a:1});
console.log([...set.values()]); // Array [ Object, Object ]
¿Cómo personalizar la igualdad para establecer objetos para hacer una comparación profunda de objetos? ¿Hay algo como Java equals(Object)
?
javascript
set
ecmascript-harmony
Czerny
fuente
fuente
===
. El objeto de conjunto ES6 no tiene ningún método de comparación. El.has()
método y el.add()
método solo funcionan si es el mismo objeto real o el mismo valor para una primitiva.Respuestas:
El
Set
objeto ES6 no tiene ningún método de comparación ni extensibilidad de comparación personalizada.Los métodos
.has()
,.add()
y.delete()
solo funcionan si es el mismo objeto real o el mismo valor para una primitiva y no tienen un medio para conectarse o reemplazar solo esa lógica.Probablemente podría derivar su propio objeto de ay
Set
reemplazar.has()
,.add()
y.delete()
métodos con algo que hizo una comparación profunda de objetos primero para encontrar si el elemento ya está en el Conjunto, pero el rendimiento probablemente no sería bueno ya que elSet
objeto subyacente no estaría ayudando en absoluto. Probablemente tendría que hacer una iteración de fuerza bruta a través de todos los objetos existentes para encontrar una coincidencia utilizando su propia comparación personalizada antes de llamar al original.add()
.Aquí hay información de este artículo y discusión sobre las características de ES6:
fuente
Set
o no?Como se menciona en la respuesta de jfriend00, la personalización de la relación de igualdad probablemente no sea posible .
El siguiente código presenta un esquema de solución computacionalmente eficiente (pero costosa en memoria) :
Cada elemento insertado tiene que implementar un
toIdString()
método que devuelva una cadena. Dos objetos se consideran iguales si y solo si sustoIdString
métodos devuelven el mismo valor.fuente
item.toIdString()
es invariante y no puede cambiar. Porque si puede,GeneralSet
puede volverse inválido fácilmente con elementos "duplicados". Por lo tanto, una solución como esa estaría restringida a ciertas situaciones probables en las que los objetos mismos no cambian mientras se usa el conjunto o donde un conjunto que se vuelve inválido no es una consecuencia. Es probable que todos estos problemas expliquen por qué el ES6 Set no expone esta funcionalidad porque realmente solo funciona en ciertas circunstancias..delete()
esta respuesta?Como se menciona en la respuesta principal , personalizar la igualdad es problemático para los objetos mutables. La buena noticia es que (y me sorprende que nadie haya mencionado esto aún) hay una biblioteca muy popular llamada immutable-js que proporciona un rico conjunto de tipos inmutables que proporcionan la semántica de igualdad de valor profundo que está buscando.
Aquí está su ejemplo usando immutable-js :
fuente
Para agregar a las respuestas aquí, seguí adelante e implementé un contenedor de mapas que toma una función hash personalizada, una función de igualdad personalizada y almacena valores distintos que tienen hashes equivalentes (personalizados) en cubos.
Como era de esperar, resultó ser más lento que el método de concatenación de cadenas de Czerny .
Fuente completa aquí: https://github.com/makoConstruct/ValueMap
fuente
Point
definido como{ x: number, y: number }
entonces,id string
probablemente sea sux.toString() + ',' + y.toString()
.String
, entonces puede omitir todo el paso de hashing y bucketing como dijo y simplemente usar directamente unMap
o incluso un objeto plano de estilo antiguo en términos de la clave derivada.{x: '1,2', y: '3'}
y{x: '1', y: '2,3'}
, entoncesString(x) + ',' + String(y)
generará el mismo valor para ambos objetos. Una opción más segura, suponiendo que pueda contar conJSON.stringify()
ser determinista, es aprovechar su escape de cadena y usarJSON.stringify([x, y])
en su lugar.No es posible compararlos directamente, pero JSON.stringify funciona si las claves se acaban de ordenar. Como señalé en un comentario
JSON.stringify ({a: 1, b: 2})! == JSON.stringify ({b: 2, a: 1});
Pero podemos evitar eso con un método de stringify personalizado. Primero escribimos el método
Stringify personalizado
El conjunto
Ahora usamos un conjunto. Pero usamos un conjunto de cadenas en lugar de objetos
Obtén todos los valores
Después de crear el conjunto y agregar los valores, podemos obtener todos los valores al
Aquí hay un enlace con todo en un archivo http://tpcg.io/FnJg2i
fuente
Tal vez pueda intentar usar
JSON.stringify()
para hacer una comparación profunda de objetos.por ejemplo :
fuente
Para los usuarios de Typecript, las respuestas de otros (especialmente czerny ) se pueden generalizar a una clase base agradable, segura y reutilizable:
La implementación de ejemplo es así de simple: simplemente anule el
stringifyKey
método. En mi caso, stringifico algunauri
propiedad.El uso de ejemplo es entonces como si fuera un habitual
Map<K, V>
.fuente
Cree un nuevo conjunto a partir de la combinación de ambos conjuntos, luego compare la longitud.
set1 es igual a set2 = verdadero
set1 es igual a set4 = falso
fuente
Para alguien que encontró esta pregunta en Google (como yo) que desea obtener un valor de un Mapa usando un objeto como Clave:
Advertencia: esta respuesta no funcionará con todos los objetos
Salida:
fuente