Le nouvel ES 6 (Harmony) introduit un nouvel objet Set . L'algorithme d'identité utilisé par Set est similaire à l' ===
opérateur et donc peu adapté à la comparaison d'objets:
var set = new Set();
set.add({a:1});
set.add({a:1});
console.log([...set.values()]); // Array [ Object, Object ]
Comment personnaliser l'égalité pour les objets Set afin de faire une comparaison d'objets approfondie? Existe-t-il quelque chose comme Java equals(Object)
?
javascript
set
ecmascript-harmony
Czerny
la source
la source
===
opérateur. L'objet set ES6 ne possède aucune méthode de comparaison. La.has()
méthode et la.add()
méthode fonctionnent uniquement sur le fait qu'il s'agit du même objet réel ou de la même valeur pour une primitive.Réponses:
L'
Set
objet ES6 n'a pas de méthode de comparaison ni d'extensibilité de comparaison personnalisée.Les méthodes
.has()
,.add()
et.delete()
ne fonctionnent que s'il s'agit du même objet réel ou de la même valeur pour une primitive et n'ont pas de moyen de se connecter ou de remplacer uniquement cette logique.Vous pourriez probablement dériver votre propre objet à partir de méthodes a
Set
et replace.has()
,.add()
et.delete()
avec quelque chose qui a d'abord effectué une comparaison d'objets approfondie pour trouver si l'élément est déjà dans l'ensemble, mais les performances ne seraient probablement pas bonnes car l'Set
objet sous-jacent n'aiderait pas. du tout. Vous devrez probablement simplement faire une itération de force brute sur tous les objets existants pour trouver une correspondance en utilisant votre propre comparaison personnalisée avant d'appeler l'original.add()
.Voici quelques informations de cet article et une discussion sur les fonctionnalités d'ES6:
la source
Set
ou pas?Comme mentionné dans la réponse de jfriend00, la personnalisation de la relation d'égalité n'est probablement pas possible .
Le code suivant présente un aperçu de la solution de contournement efficace (mais coûteuse en mémoire) :
Chaque élément inséré doit implémenter une
toIdString()
méthode qui renvoie une chaîne. Deux objets sont considérés comme égaux si et seulement si leurstoIdString
méthodes retournent la même valeur.la source
item.toIdString()
est invariante et ne peut pas changer. Parce que si c'est possible, alors leGeneralSet
peut facilement devenir invalide avec des éléments "en double" dedans. Ainsi, une solution comme celle-ci se limiterait à certaines situations probables où les objets eux-mêmes ne sont pas modifiés lors de l'utilisation de l'ensemble ou dans lesquels un ensemble qui devient invalide n'a pas de conséquence. Tous ces problèmes expliquent probablement davantage pourquoi l'ensemble ES6 n'expose pas cette fonctionnalité car elle ne fonctionne vraiment que dans certaines circonstances..delete()
à cette réponse?Comme l'indique la réponse principale , la personnalisation de l'égalité est problématique pour les objets mutables. La bonne nouvelle est (et je suis surpris que personne ne l'ait encore mentionné), il existe une bibliothèque très populaire appelée immutable-js qui fournit un riche ensemble de types immuables qui fournissent la sémantique d'égalité des valeurs profonde que vous recherchez.
Voici votre exemple utilisant immutable-js :
la source
Pour ajouter aux réponses ici, j'ai mis en œuvre un wrapper de carte qui prend une fonction de hachage personnalisée, une fonction d'égalité personnalisée et stocke des valeurs distinctes qui ont des hachages équivalents (personnalisés) dans des buckets.
Comme on pouvait s'y attendre, il s'est avéré être plus lent que la méthode de concaténation de chaînes de czerny .
Source complète ici: https://github.com/makoConstruct/ValueMap
la source
Point
défini comme,{ x: number, y: number }
votreid string
est probablementx.toString() + ',' + y.toString()
.String
, vous pouvez ignorer toute l'étape de hachage et de compartimentage comme vous l'avez dit et simplement utiliser directement unMap
ou même un objet simple à l'ancienne en termes de clé dérivée.{x: '1,2', y: '3'}
et{x: '1', y: '2,3'}
, alorsString(x) + ',' + String(y)
affichera la même valeur pour les deux objets. Une option plus sûre, en supposant que vous puissiez compter surJSON.stringify()
être déterministe, est de profiter de l'échappement de sa chaîne et de l'utiliser à laJSON.stringify([x, y])
place.Les comparer directement ne semble pas possible, mais JSON.stringify fonctionne si les clés viennent d'être triées. Comme je l'ai souligné dans un commentaire
JSON.stringify ({a: 1, b: 2})! == JSON.stringify ({b: 2, a: 1});
Mais nous pouvons contourner cela avec une méthode stringify personnalisée. Nous écrivons d'abord la méthode
Stringify personnalisé
L'ensemble
Maintenant, nous utilisons un ensemble. Mais nous utilisons un ensemble de chaînes au lieu d'objets
Obtenez toutes les valeurs
Après avoir créé l'ensemble et ajouté les valeurs, nous pouvons obtenir toutes les valeurs par
Voici un lien avec tout dans un fichier http://tpcg.io/FnJg2i
la source
Peut-être que vous pouvez essayer d'utiliser
JSON.stringify()
pour faire une comparaison d'objets approfondie.par exemple :
la source
Pour les utilisateurs de Typescript, les réponses des autres (en particulier czerny ) peuvent être généralisées à une belle classe de base de type sécurisé et réutilisable:
L'exemple d'implémentation est alors aussi simple: il suffit de remplacer la
stringifyKey
méthode. Dans mon cas, je stringify uneuri
propriété.Un exemple d'utilisation est alors comme s'il s'agissait d'un régulier
Map<K, V>
.la source
Créez un nouvel ensemble à partir de la combinaison des deux ensembles, puis comparez la longueur.
set1 est égal à set2 = true
set1 est égal à set4 = faux
la source
À quelqu'un qui a trouvé cette question sur Google (comme moi) voulant obtenir une valeur d'une carte en utilisant un objet comme clé:
Attention: cette réponse ne fonctionnera pas avec tous les objets
Production:
la source