Mit dem neuen ES 6 (Harmony) wird ein neues Set- Objekt eingeführt. Der von Set verwendete Identitätsalgorithmus ähnelt dem ===
Operator und ist daher für den Vergleich von Objekten nicht besonders geeignet:
var set = new Set();
set.add({a:1});
set.add({a:1});
console.log([...set.values()]); // Array [ Object, Object ]
Wie kann ich die Gleichheit für Set-Objekte anpassen, um einen tiefen Objektvergleich durchzuführen? Gibt es so etwas wie Java equals(Object)
?
javascript
set
ecmascript-harmony
czerny
quelle
quelle
===
Operators, daher gibt es keine Möglichkeit, den Operator zu überladen . Das ES6-Set-Objekt verfügt über keine Vergleichsmethoden. Die.has()
Methode und die.add()
Methode funktionieren nur, wenn es sich um dasselbe tatsächliche Objekt oder denselben Wert für ein Grundelement handelt.Antworten:
Das ES6-
Set
Objekt verfügt über keine Vergleichsmethoden oder benutzerdefinierte Vergleichserweiterbarkeit.Die
.has()
,.add()
und.delete()
Methoden funktionieren nur ab es das gleiche eigentliche Objekt oder denselben Wert für ein primitives Wesen und haben keine Mittel , um Stecker in oder ersetzen Sie einfach die Logik.Vermutlich könnten Sie Ihr eigenes Objekt von a ableiten und Methoden
Set
ersetzen.has()
, die zuerst einen umfassenden Objektvergleich durchgeführt haben, um festzustellen, ob sich das Element bereits im Set befindet. Die Leistung wäre jedoch wahrscheinlich nicht gut, da das zugrunde liegende Objekt nicht hilfreich wäre überhaupt. Sie müssten wahrscheinlich nur eine Brute-Force-Iteration durch alle vorhandenen Objekte durchführen, um eine Übereinstimmung mit Ihrem eigenen benutzerdefinierten Vergleich zu finden, bevor Sie das Original aufrufen ..add()
.delete()
Set
.add()
Hier einige Informationen aus diesem Artikel und eine Diskussion der ES6-Funktionen:
quelle
Set
oder nicht?Wie in der Antwort von jfriend00 erwähnt, ist eine Anpassung der Gleichheitsbeziehung wahrscheinlich nicht möglich .
Der folgende Code enthält einen Überblick über die rechnerisch effiziente (aber speicherintensive) Problemumgehung :
Jedes eingefügte Element muss eine
toIdString()
Methode implementieren , die eine Zeichenfolge zurückgibt. Zwei Objekte werden genau dann als gleich angesehen, wenn ihretoIdString
Methoden denselben Wert zurückgeben.quelle
item.toIdString()
unveränderlich ist und sich nicht ändern kann. Denn wenn dies möglich ist,GeneralSet
kann das mit "doppelten" Elementen leicht ungültig werden. Eine solche Lösung wäre also nur auf bestimmte Situationen beschränkt, in denen die Objekte selbst während der Verwendung des Satzes nicht geändert werden oder in denen ein ungültiger Satz keine Konsequenz hat. All diese Probleme erklären wahrscheinlich weiter, warum das ES6-Set diese Funktionalität nicht verfügbar macht, da es wirklich nur unter bestimmten Umständen funktioniert..delete()
, dieser Antwort die richtige Implementierung hinzuzufügen ?Wie in der Top-Antwort erwähnt, ist das Anpassen der Gleichheit für veränderbare Objekte problematisch. Die gute Nachricht ist (und ich bin überrascht, dass dies noch niemand erwähnt hat), dass es eine sehr beliebte Bibliothek namens immutable-js gibt , die eine Vielzahl unveränderlicher Typen bietet, die die von Ihnen gesuchte tiefe Gleichheitssemantik bieten.
Hier ist Ihr Beispiel mit unveränderlichen-js :
quelle
Um die Antworten hier zu ergänzen, habe ich einen Map-Wrapper implementiert, der eine benutzerdefinierte Hash-Funktion und eine benutzerdefinierte Gleichheitsfunktion verwendet und unterschiedliche Werte mit äquivalenten (benutzerdefinierten) Hashes in Buckets speichert.
Vorhersehbar stellte sich heraus, dass es langsamer war als die String-Verkettungsmethode von czerny .
Vollständige Quelle hier: https://github.com/makoConstruct/ValueMap
quelle
Point
definiert haben,{ x: number, y: number }
dann ist Ihreid string
wahrscheinlichx.toString() + ',' + y.toString()
.String
, können Sie den gesamten Hashing- und Bucketing-Schritt wie gesagt überspringen und direkt a verwendenMap
oder sogar ein einfaches Objekt alten Stils in Bezug auf den abgeleiteten Schlüssel.{x: '1,2', y: '3'}
und haben{x: '1', y: '2,3'}
,String(x) + ',' + String(y)
wird für beide Objekte der gleiche Wert ausgegeben. Eine sicherere Option, vorausgesetzt, Sie können sich darauf verlassenJSON.stringify()
, deterministisch zu sein, besteht darin, die Escapezeichenfolge zu nutzen undJSON.stringify([x, y])
stattdessen zu verwenden.Ein direkter Vergleich scheint nicht möglich zu sein, aber JSON.stringify funktioniert, wenn die Schlüssel nur sortiert wurden. Wie ich in einem Kommentar betonte
JSON.stringify ({a: 1, b: 2})! == JSON.stringify ({b: 2, a: 1});
Aber wir können das mit einer benutzerdefinierten Stringify-Methode umgehen. Zuerst schreiben wir die Methode
Benutzerdefinierte Stringify
Der Satz
Jetzt benutzen wir ein Set. Wir verwenden jedoch eine Reihe von Zeichenfolgen anstelle von Objekten
Holen Sie sich alle Werte
Nachdem wir die Menge erstellt und die Werte hinzugefügt haben, können wir alle Werte von abrufen
Hier ist ein Link mit allen in einer Datei http://tpcg.io/FnJg2i
quelle
Vielleicht können Sie versuchen, einen
JSON.stringify()
tiefen Objektvergleich durchzuführen.zum Beispiel :
quelle
Für Typescript-Benutzer können die Antworten anderer (insbesondere von czerny ) auf eine nette typsichere und wiederverwendbare Basisklasse verallgemeinert werden:
Die Beispielimplementierung ist dann so einfach: Überschreiben Sie einfach die
stringifyKey
Methode. In meinem Fall stringifiziere ich eineuri
Eigenschaft.Beispielgebrauch ist dann, als ob dies ein regulärer war
Map<K, V>
.quelle
Erstellen Sie einen neuen Satz aus der Kombination beider Sätze und vergleichen Sie dann die Länge.
set1 ist gleich set2 = true
set1 ist gleich set4 = false
quelle
Für jemanden, der diese Frage bei Google gefunden hat (wie ich), der einen Wert einer Karte mit einem Objekt als Schlüssel erhalten möchte:
Warnung: Diese Antwort funktioniert nicht mit allen Objekten
Ausgabe:
quelle