Szukam ogólnej, dwukierunkowej klasy słownika 1 do 1 w języku C # (2), tj. a, BiDictionaryOneToOne<T, S>
który gwarantuje, że zawiera tylko jedną z każdej wartości i klucza (w każdym razie do RefEquals) i który można przeszukiwać za pomocą klucza lub wartości. Ktoś go zna, czy powinienem sam go wdrożyć? Nie mogę uwierzyć, że jestem pierwszą osobą, która tego potrzebuje ...
W odpowiedziach na to pytanie znajduje się BiDictionary , ale nie jest on przeznaczony dla unikalnych elementów (a także nie implementuje RemoveByFirst (T t) ani RemoveBySecond (S)).
Dzięki!
c#
.net
collections
Joel w Gö
źródło
źródło
Odpowiedzi:
OK, oto moja próba (opierając się na Jon's - dzięki), zarchiwizowana tutaj i otwarta do ulepszeń:
źródło
Pełniejsza implementacja słownika dwukierunkowego:
Dictionary<TKey,TValue>
(z wyjątkiem interfejsów infrastruktury):IDictionary<TKey, TValue>
IReadOnlyDictionary<TKey, TValue>
IDictionary
ICollection<KeyValuePair<TKey, TValue>>
(ten i poniżej to podstawowe interfejsy powyższych)ICollection
IReadOnlyCollection<KeyValuePair<TKey, TValue>>
IEnumerable<KeyValuePair<TKey, TValue>>
IEnumerable
SerializableAttribute
.DebuggerDisplayAttribute
(z informacjami o liczniku) iDebuggerTypeProxyAttribute
(do wyświetlania par klucz-wartość w zegarkach).IDictionary<TValue, TKey> Reverse
właściwość i również implementuje wszystkie wymienione powyżej interfejsy. Wszystkie operacje na obu słownikach modyfikują oba.Stosowanie:
Kod jest dostępny w moim prywatnym frameworku na GitHub: BiDictionary (TFirst, TSecond) .cs ( permalink , search ).
Kopiuj:
źródło
item.Reverse
liniach pojawia się błąd kompilacji . Jakieś szczególne wymagania dotyczące wersji?KeyValuePairExts
klasy na dole fragmentu kodu.Pytanie, do którego się odnosisz, również pokazuje implementację jeden do jednego w tej odpowiedzi . Dodanie RemoveByFirst i RemoveBySecond byłoby trywialne - podobnie jak implementacja dodatkowych interfejsów itp.
źródło
To jest to samo, co zaakceptowana odpowiedź, ale
Update
podałem również metody, a przede wszystkim trochę bardziej rozwinięte:Podobna do mojej odpowiedzi tutaj
Kilka rzeczy do zapamiętania:
Wdrożyłem tylko
IEnumerable<>
. Myślę, że nieICollection<>
ma to sensu, ponieważ nazwy metod mogą być zupełnie inne dla tej specjalnej struktury kolekcji. Do Ciebie należy decyzja, co powinno znaleźć się w środkuIEnumerable<>
. Więc teraz masz również składnię inicjatora kolekcji, na przykładPróbowałem wrzucić tu i tam kilka dziwnych wyjątków - tylko dla integralności danych. Po prostu być po bezpieczniejszej stronie, aby wiedzieć, czy kiedykolwiek mój kod zawiera błędy.
Wydajność: możesz wyszukiwać za
Value
pomocą dowolnego zKeys
, co oznaczaGet
iContains
metoda wymaga tylko jednego wyszukiwania (O (1)).Add
wymaga 2 wyszukiwań i 2 dodawania.Update
wymaga 1 wyszukiwania i 2 dodaje.Remove
wykonuje 3 wyszukiwania. Wszystko podobne do zaakceptowanej odpowiedzi.źródło
IEnumerator<Tuple<TKey1, TKey2>>
tutaj. NieIEnumerator<KeyValuePair<TKey1, TKey2>>
, więc myślę, że nie mogę tego zrobić z moją funkcją GetEnumerator. Czy poprawnie cię dostałem?Stworzyłem taką klasę, korzystając z klas kolekcji C5.
źródło
Kolejne rozszerzenie zaakceptowanej odpowiedzi. Implementuje IEnumerable, więc można z tym używać foreach. Zdaję sobie sprawę, że jest więcej odpowiedzi z implementacją IEnumerable, ale ta używa struktur, więc jest przyjazna dla garbage collectora . Jest to szczególnie przydatne w silniku Unity (sprawdzane za pomocą profilera).
źródło
Trochę późno, ale oto implementacja, którą napisałem jakiś czas temu. Obsługuje kilka interesujących przypadków skrajnych, na przykład gdy klucz zastępuje sprawdzenie równości w celu wykonania częściowej równości. Powoduje to przechowywanie w głównym słowniku,
A => 1
ale przechowywanie odwrotne1 => A'
.Dostęp do słownika odwrotnego można uzyskać za pośrednictwem
Inverse
właściwości.Oryginalne źródło i testy na github.
źródło