Chciałbym porównać zawartość kilku kolekcji w mojej metodzie Equals. Mam słownik i IList. Czy istnieje wbudowana metoda, aby to zrobić?
Edytowane: Chcę porównać dwa słowniki i dwa IListy, więc myślę, że to, co oznacza równość, jest jasne - jeśli dwa słowniki zawierają te same klucze odwzorowane na te same wartości, to są one równe.
c#
.net
collections
TimK
źródło
źródło
IList
? Pytanie jest dwuznaczne.Enumerable.SequenceEqual
iISet.SetEquals
podaj wersje tej funkcjonalności. Jeśli chcesz być niezależny od zamówień i pracować z kolekcjami, które mają duplikaty, musisz rzucić własne. Sprawdź implementację sugerowaną w tym pościeOdpowiedzi:
Enumerable.SequenceEqual
Nie można bezpośrednio porównać listy i słownika, ale można porównać listę wartości ze słownika z listą
źródło
.Keys
a zatem.Values
może zwracać klucze i wartości w dowolnej kolejności, a ich kolejność może się zmieniać w miarę modyfikowania słownika. Sugeruję przeczytanie, czym jest Słownik, a czym nie jest.Jak inni sugerowali i zauważyli,
SequenceEqual
jest wrażliwy na zamówienia. Aby rozwiązać ten problem, możesz posortować słownik według klucza (który jest unikalny, a zatem sortowanie jest zawsze stabilne), a następnie użyćSequenceEqual
. Poniższe wyrażenie sprawdza, czy dwa słowniki są równe bez względu na ich porządek wewnętrzny:EDYCJA: Jak zauważył Jeppe Stig Nielsen, niektóre obiekty mają
IComparer<T>
niezgodne z nimi obiektyIEqualityComparer<T>
, co daje nieprawidłowe wyniki. Używając kluczy z takim obiektem, musisz określić poprawnośćIComparer<T>
tych kluczy. Na przykład w przypadku kluczy łańcuchowych (które wykazują ten problem) należy wykonać następujące czynności, aby uzyskać prawidłowe wyniki:źródło
CompareTo
? Twoje rozwiązanie wybuchnie wtedy. A jeśli typ klucza ma domyślny moduł porównujący, który jest niezgodny z jego domyślnym modułem porównującym? Tak jest w przypadkustring
. Na przykład te słowniki (z domyślnymi porównywalnikami równości) zakończą się niepowodzeniem (pod wszystkimi informacjami o kulturze, o których wiem):var dictionary1 = new Dictionary<string, int> { { "Strasse", 10 }, { "Straße", 20 }, }; var dictionary2 = new Dictionary<string, int> { { "Straße", 20 }, { "Strasse", 10 }, };
IComparer
iIEqualityComparer
- nie byłem świadomy tego problemu, bardzo interesujące! Zaktualizowałem odpowiedź możliwym rozwiązaniem. Jeśli chodzi o brakCompareTo
, myślę, że programista powinien upewnić się, że delegat przekazany doOrderBy()
metody zwraca coś porównywalnego. Myślę, że jest to prawdą w przypadku każdego zastosowaniaOrderBy()
, a nawet poza porównaniami słownikowymi.Oprócz wspomnianego SequenceEqual , który
(który może być domyślnym programem porównującym, tzn. przesłonięciem
Equals()
)warto wspomnieć, że w .Net4 jest SetEquals na
ISet
obiektach, któreWięc jeśli chcesz mieć listę obiektów, ale nie muszą one znajdować się w określonej kolejności, zastanów się, że
ISet
(jak aHashSet
) może być właściwym wyborem.źródło
Spójrz na metodę Enumerable.SequenceEqual
źródło
.NET Brakuje potężnych narzędzi do porównywania kolekcji. Opracowałem proste rozwiązanie, które można znaleźć pod linkiem poniżej:
http://robertbouillon.com/2010/04/29/comparing-collections-in-net/
Spowoduje to porównanie równości bez względu na kolejność:
Spowoduje to sprawdzenie, czy elementy zostały dodane / usunięte:
To zobaczy, które elementy w słowniku się zmieniły:
źródło
.Removed
jest taki sam jaklist1.Except(list2)
,.Added
jestlist2.Except(list1)
,.Equal
jestlist1.Intersect(list2)
i.Different
jestoriginal.Join(changed, left => left.Key, right => right.Key, (left, right) => left.Value == right.Value)
. Możesz wykonać prawie każde porównanie z LINQ..Different
jestoriginal.Join(changed, left => left.Key, right => right.Key, (left, right) => new { Key = left.Key, NewValue = right.Value, Different = left.Value == right.Value).Where(d => d.Different)
. Możesz nawet dodać,OldValue = left.Value
jeśli potrzebujesz starej wartości.Nie wiedziałem o metodzie Enumerable.SequenceEqual (uczysz się czegoś codziennie ....), ale zamierzałem zasugerować użycie metody rozszerzenia; coś takiego:
Co ciekawe, po poświęceniu 2 sekund na przeczytanie o SequenceEqual wygląda na to, że Microsoft zbudował dla ciebie funkcję, którą opisałem.
źródło
To nie jest bezpośrednia odpowiedź na twoje pytania, ale zarówno MS TestTools, jak i NUnit zapewniają
który robi prawie wszystko, co chcesz.
źródło
Aby porównać kolekcje, możesz również użyć LINQ.
Enumerable.Intersect
zwraca wszystkie pary, które są równe. Możesz porównać dwa takie słowniki:Pierwsze porównanie jest potrzebne, ponieważ
dict2
może zawierać wszystkie klucze oddict1
i więcej.Można również użyć myśleć odmianach wykorzystujących
Enumerable.Except
iEnumerable.Union
które prowadzą do podobnych wyników. Ale można go użyć do ustalenia dokładnych różnic między zestawami.źródło
Co powiesz na ten przykład:
Dzięki uprzejmości: https://www.dotnetperls.com/dictionary-equals
źródło
Do uporządkowanych kolekcji (Lista, Tablica) użyj
SequenceEqual
do użytku HashSet
SetEquals
W przypadku słownika możesz:
(Bardziej zoptymalizowane rozwiązanie będzie korzystało z sortowania, ale będzie wymagało
IComparable<TValue>
)źródło
Nie. Ramy kolekcji nie mają żadnej koncepcji równości. Jeśli się nad tym zastanowić, nie ma sposobu na porównanie kolekcji, które nie są subiektywne. Na przykład porównując swoją IListę ze Słownikiem, czy byłyby one równe, gdyby wszystkie klucze były w IList, wszystkie wartości były w IList, czy oba były w IList? Nie ma oczywistego sposobu na porównanie tych dwóch kolekcji bez wiedzy o tym, do czego mają być użyte, więc metoda równości ogólnego przeznaczenia nie ma sensu.
źródło
Nie, ponieważ środowisko nie wie, jak porównać zawartość list.
Zerknij na to:
http://blogs.msdn.com/abhinaba/archive/2005/10/11/479537.aspx
źródło
IComparer<T>
, Nadrzędneobject.Equals
,IEquatable<T>
,IComparable<T>
...źródło
Nie było, nie ma i może nie być, przynajmniej w to uwierzę. Przyczyną takiego stanu rzeczy jest prawdopodobnie zachowanie zdefiniowane przez użytkownika.
Elementy w kolekcjach nie powinny znajdować się w określonej kolejności, chociaż mają naturalnie uporządkowanie, nie na tym powinny polegać algorytmy porównujące. Załóżmy, że masz dwie kolekcje:
Czy są równi czy nie? Musisz wiedzieć, ale nie wiem jaki jest twój punkt widzenia.
Kolekcje są domyślnie nieuporządkowane koncepcyjnie, dopóki algorytmy nie zapewnią reguł sortowania. Ta sama rzecz, na którą zwraca uwagę serwer SQL, podczas próby podziału na strony, wymaga podania reguł sortowania:
https://docs.microsoft.com/en-US/sql/t-sql/queries/select-order-by-clause-transact-sql?view=sql-server-2017
Kolejne dwie kolekcje:
Znów są równe czy nie? Ty mi powiedz ..
Powtarzalność elementów kolekcji odgrywa swoją rolę w różnych scenariuszach, a niektóre kolekcje, takie jak
Dictionary<TKey, TValue>
, nawet nie zezwalają na powtarzające się elementy.Uważam, że tego rodzaju równość jest definiowana przez aplikację, dlatego ramy nie zapewniły wszystkich możliwych implementacji.
Cóż, w ogólnych przypadkach
Enumerable.SequenceEqual
jest wystarczająco dobry, ale zwraca false w następującym przypadku:Przeczytałem niektóre odpowiedzi na takie pytania (możesz je znaleźć w Google ) i ogólnie, czego bym użył:
Oznacza to, że jedna kolekcja reprezentuje drugą w swoich elementach, w tym wielokrotnie powtarzanych, bez uwzględnienia pierwotnego porządku. Niektóre uwagi dotyczące wdrożenia:
GetHashCode()
służy tylko porządkowi, a nie równości; Myślę, że w tym przypadku wystarczyCount()
tak naprawdę nie wyliczy kolekcji i bezpośrednio wpisze się w implementację właściwościICollection<T>.Count
Jeśli referencje są równe, to tylko Boris
źródło