Nowy ES 6 (Harmony) wprowadza nowy obiekt Set . Algorytm tożsamości używany przez Set jest podobny do ===
operatora, więc nie nadaje się zbytnio do porównywania obiektów:
var set = new Set();
set.add({a:1});
set.add({a:1});
console.log([...set.values()]); // Array [ Object, Object ]
Jak dostosować równość dla obiektów Set, aby przeprowadzić głębokie porównanie obiektów? Czy jest coś takiego jak Java equals(Object)
?
javascript
set
ecmascript-harmony
czerny
źródło
źródło
===
operatora. Obiekt set ES6 nie ma żadnych metod porównawczych..has()
Metoda i.add()
sposób nowy utwór tylko na off to jest to samo rzeczywisty przedmiot lub sama wartość dla prymitywne.Odpowiedzi:
Obiekt ES6
Set
nie ma żadnych metod porównywania ani niestandardowej rozszerzalności porównywania.Metody
.has()
,.add()
i.delete()
działają tylko wtedy, gdy są tym samym rzeczywistym obiektem lub tą samą wartością dla prymitywu i nie mają środków do podłączenia lub zastąpienia tylko tej logiki.Można przypuszczalnie wyprowadzić własny obiekt z a
Set
i replace.has()
,.add()
a także.delete()
metody z czymś, co najpierw wykonało głębokie porównanie obiektów, aby dowiedzieć się, czy element jest już w zestawie, ale wydajność prawdopodobnie nie byłaby dobra, ponieważ podstawowySet
obiekt nie pomagałby w ogóle. Prawdopodobnie musiałbyś po prostu wykonać iterację brutalnej siły przez wszystkie istniejące obiekty, aby znaleźć dopasowanie za pomocą własnego niestandardowego porównania przed wywołaniem oryginału.add()
.Oto kilka informacji z tego artykułu i omówienie funkcji ES6:
źródło
Set
czy nie?Jak wspomniano w odpowiedzi jfriend00, dostosowanie relacji równości prawdopodobnie nie jest możliwe .
Poniższy kod przedstawia zarys wydajnego obliczeniowo (ale kosztownego w pamięci) obejścia :
Każdy wstawiany element musi zaimplementować
toIdString()
metodę, która zwraca ciąg. Dwa obiekty są uważane za równe wtedy i tylko wtedy, gdy ichtoIdString
metody zwracają tę samą wartość.źródło
item.toIdString()
jest niezmienna i nie może się zmienić. Bo jeśli może, toGeneralSet
łatwo może stać się nieważne z „zduplikowanymi” elementami. Tak więc takie rozwiązanie byłoby ograniczone tylko do pewnych sytuacji, w których same obiekty nie są zmieniane podczas używania zestawu lub gdy zbiór, który staje się nieważny, nie ma znaczenia. Wszystkie te kwestie prawdopodobnie dodatkowo wyjaśniają, dlaczego zestaw ES6 nie udostępnia tej funkcji, ponieważ działa ona tylko w określonych okolicznościach..delete()
do tej odpowiedzi?Jak wspomniano w pierwszej odpowiedzi , dostosowywanie równości jest problematyczne w przypadku obiektów zmiennych. Dobrą wiadomością jest to, że (i jestem zaskoczony, że nikt jeszcze o tym nie wspomniał) istnieje bardzo popularna biblioteka o nazwie immutable-js, która zapewnia bogaty zestaw niezmiennych typów, które zapewniają głęboką semantykę równości wartości , której szukasz.
Oto przykład użycia immutable-js :
źródło
Aby dodać do odpowiedzi tutaj, poszedłem dalej i zaimplementowałem otokę mapy, która przyjmuje niestandardową funkcję skrótu, niestandardową funkcję równości i przechowuje różne wartości, które mają równoważne (niestandardowe) skróty w zasobnikach.
Jak można się było spodziewać , okazał się wolniejszy niż metoda konkatenacji strun czernego .
Pełne źródło tutaj: https://github.com/makoConstruct/ValueMap
źródło
Point
zdefiniowane jako{ x: number, y: number }
wówczasid string
prawdopodobniex.toString() + ',' + y.toString()
.String
, możesz pominąć cały krok haszowania i grupowania, jak powiedziałeś i po prostu bezpośrednio użyjMap
lub nawet zwykły obiekt w starym stylu pod względem klucza pochodnego.{x: '1,2', y: '3'}
i{x: '1', y: '2,3'}
, toString(x) + ',' + String(y)
wyświetli tę samą wartość dla obu obiektów. Bezpieczniejszą opcją, zakładając, że możesz liczyć naJSON.stringify()
bycie deterministą, jest skorzystanie z funkcji ucieczki ciągu i użycieJSON.stringify([x, y])
zamiast tego.Bezpośrednie porównanie ich wydaje się niemożliwe, ale JSON.stringify działa, jeśli klucze zostały właśnie posortowane. Jak wskazałem w komentarzu
JSON.stringify ({a: 1, b: 2})! == JSON.stringify ({b: 2, a: 1});
Ale możemy to obejść za pomocą niestandardowej metody stringify. Najpierw piszemy metodę
Niestandardowe Stringify
Zestaw
Teraz używamy zestawu. Ale zamiast obiektów używamy zestawu ciągów
Uzyskaj wszystkie wartości
Po utworzeniu zestawu i dodaniu wartości, możemy uzyskać wszystkie wartości według
Oto link ze wszystkim w jednym pliku http://tpcg.io/FnJg2i
źródło
Może możesz spróbować użyć
JSON.stringify()
do przeprowadzenia głębokiego porównania obiektów.na przykład :
źródło
W przypadku użytkowników maszynopisu odpowiedzi innych osób (zwłaszcza czerny ) można uogólnić na ładną, bezpieczną dla typów i wielokrotnego użytku klasę bazową:
Przykładowa implementacja jest więc taka prosta: po prostu zastąp
stringifyKey
metodę. W moim przypadku określam pewnąuri
własność.Przykładowe użycie jest wtedy tak, jakby to było zwykłe
Map<K, V>
.źródło
Utwórz nowy zestaw z połączenia obu zestawów, a następnie porównaj długość.
zestaw1 równa się zestaw2 = prawda
set1 równa się set4 = false
źródło
Do kogoś, kto znalazł to pytanie w Google (tak jak ja), chcąc uzyskać wartość mapy przy użyciu obiektu jako klucza:
Ostrzeżenie: ta odpowiedź nie będzie działać dla wszystkich obiektów
Wynik:
źródło