O novo ES 6 (Harmony) apresenta o novo objeto Set . O algoritmo de identidade usado pelo Set é semelhante ao ===
operador e, portanto, não é muito adequado para comparar objetos:
var set = new Set();
set.add({a:1});
set.add({a:1});
console.log([...set.values()]); // Array [ Object, Object ]
Como personalizar a igualdade dos objetos Set para fazer uma comparação profunda dos objetos? Existe algo como Java equals(Object)
?
javascript
set
ecmascript-harmony
Czerny
fonte
fonte
===
operador. O objeto do conjunto ES6 não possui nenhum método de comparação. O.has()
método e o.add()
método funcionam apenas com o mesmo objeto real ou o mesmo valor para uma primitiva.Respostas:
O
Set
objeto ES6 não possui nenhum método de comparação ou extensibilidade de comparação personalizada.Os métodos
.has()
,.add()
e.delete()
funcionam apenas com o mesmo objeto real ou o mesmo valor de uma primitiva e não têm como conectar ou substituir apenas essa lógica.Presumivelmente, você poderia derivar seu próprio objeto de
Set
ae replace.has()
,.add()
e.delete()
métodos por algo que fez uma comparação profunda de objetos primeiro para descobrir se o item já está no Conjunto, mas o desempenho provavelmente não seria bom, pois oSet
objeto subjacente não ajudaria em absoluto. Você provavelmente precisaria fazer uma iteração de força bruta em todos os objetos existentes para encontrar uma correspondência usando sua própria comparação personalizada antes de chamar o original.add()
.Aqui estão algumas informações deste artigo e discussão dos recursos do ES6:
fonte
Set
ou não?Como mencionado na resposta de jfriend00, a personalização da relação de igualdade provavelmente não é possível .
O código a seguir apresenta um esboço da solução alternativa computacionalmente eficiente (mas com memória dispendiosa) :
Cada elemento inserido deve implementar o
toIdString()
método que retorna string. Dois objetos são considerados iguais se e somente se seustoIdString
métodos retornarem o mesmo valor.fonte
item.toIdString()
é invariável e não pode mudar. Porque se puder,GeneralSet
pode facilmente tornar-se inválido com itens "duplicados". Portanto, uma solução como essa seria restrita a apenas certas situações prováveis em que os objetos em si não são alterados durante o uso do conjunto ou onde um conjunto que se torna inválido não tem conseqüência. Todos esses problemas provavelmente explicam melhor por que o ES6 Set não expõe essa funcionalidade porque realmente funciona apenas em determinadas circunstâncias..delete()
para esta resposta?Como a resposta principal menciona, personalizar a igualdade é problemático para objetos mutáveis. A boa notícia é (e estou surpreso que ninguém tenha mencionado isso ainda) que existe uma biblioteca muito popular chamada immutable-js que fornece um rico conjunto de tipos imutáveis que fornecem a profunda semântica de igualdade de valor que você está procurando.
Aqui está o seu exemplo usando immutable-js :
fonte
Para adicionar as respostas aqui, fui adiante e implementei um invólucro de mapa que usa uma função de hash personalizada, uma função de igualdade personalizada e armazena valores distintos que possuem hashes (personalizados) equivalentes em buckets.
Previsivelmente, acabou sendo mais lento que o método de concatenação de strings do czerny .
Fonte completa aqui: https://github.com/makoConstruct/ValueMap
fonte
Point
definido como o{ x: number, y: number }
seuid string
provavelmente éx.toString() + ',' + y.toString()
.String
, então você pode pular toda a etapa de hash e balde como você disse e usar apenas diretamente umMap
ou mesmo objeto simples de estilo antigo em termos da chave derivada.{x: '1,2', y: '3'}
e{x: '1', y: '2,3'}
, em seguidaString(x) + ',' + String(y)
, produzirá o mesmo valor para os dois objetos. Uma opção mais segura, assumindo que você podeJSON.stringify()
ser determinista, é tirar proveito do escape de sua string e usá-laJSON.stringify([x, y])
.Compará-los diretamente parece não ser possível, mas o JSON.stringify funciona se as chaves foram classificadas. Como apontei em um comentário
JSON.stringify ({a: 1, b: 2})! == JSON.stringify ({b: 2, a: 1});
Mas podemos contornar isso com um método stringify personalizado. Primeiro, escrevemos o método
Stringify personalizado
O conjunto
Agora usamos um conjunto. Mas usamos um conjunto de seqüências de caracteres em vez de objetos
Obter todos os valores
Depois de criarmos o conjunto e adicionarmos os valores, podemos obter todos os valores por
Aqui está um link com tudo em um arquivo http://tpcg.io/FnJg2i
fonte
Talvez você possa tentar usar
JSON.stringify()
para fazer uma comparação profunda de objetos.por exemplo :
fonte
Para usuários do Typecript, as respostas de outras pessoas (especialmente do czerny ) podem ser generalizadas para uma boa classe base segura e reutilizável:
A implementação de exemplo é assim simples: basta substituir o
stringifyKey
método. No meu caso, eu especifico algumauri
propriedade.O uso de exemplo é como se isso fosse regular
Map<K, V>
.fonte
Crie um novo conjunto a partir da combinação dos dois conjuntos e compare o comprimento.
set1 é igual a set2 = true
set1 é igual a set4 = false
fonte
Para alguém que encontrou essa pergunta no Google (como eu) que deseja obter o valor de um mapa usando um objeto como Chave:
Atenção: esta resposta não funcionará com todos os objetos
Resultado:
fonte