Como personalizar a igualdade de objects para o conjunto de JavaScript

O novo ES 6 (Harmony) introduz o novo object Set . O algoritmo de identidade usado por Set é semelhante ao operador === e, portanto, não é muito adequado para comparar objects:

 var set = new Set(); set.add({a:1}); set.add({a:1}); console.log([...set.values()]); // Array [ Object, Object ] 

Como personalizar a igualdade de objects Set para fazer uma comparação profunda de objects? Existe alguma coisa como Java equals(Object) ?

O object ES6 Set não possui nenhum método de comparação ou extensibilidade de comparação personalizada.

Os .has() , .add() e .delete() funcionam apenas com o mesmo object real ou mesmo valor para uma primitiva e não possuem meios para se conectar ou replace apenas essa lógica.

Você poderia presumivelmente derivar seu próprio object de um Set e replace os .has() , .add() e .delete() por algo que fez uma comparação profunda de objects primeiro para descobrir se o item já está no Conjunto, mas o desempenho provavelmente não seria bom, pois o object Set subjacente não estaria ajudando em nada. Você provavelmente teria que fazer apenas uma iteração de força bruta em todos os objects 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 sobre os resources do ES6:

5.2 Por que não posso configurar como os mapas e conjuntos comparam chaves e valores?

Pergunta: Seria bom se houvesse uma maneira de configurar quais chaves do mapa e quais elementos do conjunto são considerados iguais. Por que não existe?

Resposta: Esse recurso foi adiado, pois é difícil implementar de forma adequada e eficiente. Uma opção é entregar retornos de chamada para collections que especificam igualdade.

Outra opção, disponível em Java, é especificar igualdade por meio de um método que o object implemente (equals () em Java). No entanto, essa abordagem é problemática para objects mutáveis: em geral, se um object mudar, sua “localização” dentro de uma coleção também terá que ser alterada. Mas não é isso que acontece em Java. O JavaScript provavelmente será a rota mais segura de apenas permitir a comparação por valor para objects imutáveis ​​especiais (chamados objects de valor). Comparação por valor significa que dois valores são considerados iguais se seus conteúdos forem iguais. Valores primitivos são comparados por valor em JavaScript.

Como mencionado na resposta do jfriend00, a personalização da relação de igualdade provavelmente não é possível .

O código a seguir apresenta uma estrutura de tópicos de solução computacionalmente eficiente (mas com alto custo de memory):

 class GeneralSet { constructor() { this.map = new Map(); this[Symbol.iterator] = this.values; } add(item) { this.map.set(item.toIdString(), item); } values() { return this.map.values(); } // ... } 

Cada elemento inserido deve implementar o método toIdString() que retorna string. Dois objects são considerados iguais se e somente se seus methods toIdString retornarem o mesmo valor.

Para adicionar as respostas aqui, eu segui em frente e implementei um wrapper Map que usa uma function hash customizada, uma function de igualdade customizada e armazena valores distintos que possuem hashes equivalentes (customizados) em buckets.

Previsivelmente, acabou sendo mais lento que o método de concatenação de strings de czerny .

Fonte completa aqui: https://github.com/makoConstruct/ValueMap

Talvez você possa tentar usar JSON.stringify() para fazer uma comparação profunda de objects.

por exemplo :

 const arr = [ {name:'a', value:10}, {name:'a', value:20}, {name:'a', value:20}, {name:'b', value:30}, {name:'b', value:40}, {name:'b', value:40} ]; const names = new Set(); const result = arr.filter(item => !names.has(JSON.stringify(item)) ? names.add(JSON.stringify(item)) : false); console.log(result);