Z pozycji MSDN w Dictionary.TryGetValue Metoda :
Ta metoda łączy funkcjonalność metody ContainsKey i właściwości Item.
Jeśli klucz nie zostanie znaleziony, wówczas parametr value otrzymuje odpowiednią wartość domyślną dla typu wartości TValue; na przykład 0 (zero) dla typów całkowitych, false dla typów boolowskich, a null dla typów referencyjnych.
Użyj metody TryGetValue, jeśli kod często próbuje uzyskać dostęp do kluczy, których nie ma w słowniku. Użycie tej metody jest bardziej wydajne niż wyłapanie wyjątku KeyNotFoundException zgłaszanego przez właściwość Item.
Ta metoda zbliża się do operacji O (1).
Z opisu nie jest jasne, czy jest bardziej wydajne czy po prostu wygodniejsze niż wywołanie ContainsKey, a następnie wykonanie wyszukiwania. Czy implementacja TryGetValue
wywołania ContainsKey, a następnie Item, czy też jest faktycznie bardziej wydajna, wykonując jedno wyszukiwanie?
Innymi słowy, co jest bardziej wydajne (tj. Który wykonuje mniej wyszukiwań):
Dictionary<int,int> dict;
//...//
int ival;
if(dict.ContainsKey(ikey))
{
ival = dict[ikey];
}
else
{
ival = default(int);
}
lub
Dictionary<int,int> dict;
//...//
int ival;
dict.TryGetValue(ikey, out ival);
Uwaga: nie szukam punktu odniesienia!
źródło
if(dict.ContainsKey(ikey)) dict[ikey]++; else dict.Add(ikey, 0);
. Ale myślę, żeTryGetValue
jest to jeszcze bardziej wydajne, ponieważ używany jest get i set właściwości indeksatora, prawda?Szybki test porównawczy pokazuje, że
TryGetValue
ma niewielką przewagę:To produkuje
dzięki czemu
ContainsKey + Item
dostęp do około 40% wolniej zakładając nawet mieszanka trafień i tęskni.Ponadto, gdy zmieniam program tak, aby zawsze tęsknił (tj. Zawsze patrzył w górę
"b"
), dwie wersje stały się równie szybkie:Kiedy jednak robię to „wszystkie hity”,
TryGetValue
pozostaje wyraźnym zwycięzcą:źródło
TryGetValue
powinieneś być daleko. Również ... nitpick ...DateTime
nie jest najlepszym sposobem na przechwytywanie pomiarów wydajności.TryGetValue
dostajesz się jeszcze bardziej na prowadzenie. Zredagowałem odpowiedź, aby uwzględnić scenariusze „wszystkich trafień” i „wszystkich brakujących”.Any
- Jak to:Any(i=>i.Key==key)
. W takim przypadku tak, jest to złe wyszukiwanie liniowe słownika.DateTime.Now
będzie dokładny tylko do kilku ms. Zamiast tego użyjStopwatch
klasySystem.Diagnostics
(która używa QueryPerformanceCounter pod przykryciem, aby zapewnić znacznie wyższą dokładność). Jest również łatwiejszy w użyciu.Ponieważ żadna z dotychczasowych odpowiedzi nie odpowiada na pytanie, oto akceptowalna odpowiedź, którą znalazłem po kilku badaniach:
Jeśli dekompilujesz TryGetValue, zobaczysz, że robi to:
podczas gdy metoda ContainsKey to:
więc TryGetValue to tylko ContainsKey plus wyszukiwanie tablicy, jeśli element jest obecny.
Źródło
Wygląda na to, że TryGetValue będzie prawie dwa razy szybszy niż kombinacja ContainsKey + Item.
źródło
Kogo to obchodzi :-)
Prawdopodobnie pytasz, ponieważ
TryGetValue
jest to trudny w użyciu - więc obuduj go w ten sposób metodą rozszerzenia.Następnie wystarczy zadzwonić:
lub
źródło
this
ale okazuje się, że moja metoda została zduplikowana dwukrotnie w mojej bazie kodu - raz z i bez bez,this
więc nigdy tego nie złapałem! dzięki za naprawę!TryGetValue
przypisuje wartość domyślną do parametru wartości wyjściowej, jeśli klucz nie istnieje, więc można to uprościć.if(!dic.TryGetValue(key, out value item)) item = dic[key] = new Item();
Dlaczego tego nie przetestujesz?
Ale jestem pewien, że
TryGetValue
jest to szybsze, ponieważ wykonuje tylko jedno wyszukiwanie. Oczywiście nie jest to gwarantowane, tzn. Różne implementacje mogą mieć różne charakterystyki wydajności.Zaimplementowałbym słownik, tworząc wewnętrzną
Find
funkcję, która wyszukuje miejsce dla przedmiotu, a następnie buduję resztę na nim.źródło
Wszystkie dotychczasowe odpowiedzi, choć dobre, nie mają istotnego znaczenia.
Metody do klas API (np. .NET Framework) stanowią część definicji interfejsu (nie interfejsu C # lub VB, ale interfejs w znaczeniu informatyki).
W związku z tym zwykle niewłaściwe jest pytanie, czy wywołanie takiej metody jest szybsze, chyba że prędkość jest częścią formalnej definicji interfejsu (czego nie ma w tym przypadku).
Tradycyjnie ten rodzaj skrótu (łączący wyszukiwanie i pobieranie) jest bardziej wydajny bez względu na język, infrastrukturę, system operacyjny, platformę lub architekturę maszyny. Jest także bardziej czytelny, ponieważ wyraźnie wyraża twoją intencję, a nie sugeruje (ze struktury twojego kodu).
Tak więc odpowiedź (ze starego, posiwiałego hacka) jest zdecydowanie „Tak” (TryGetValue jest lepsza niż kombinacja ContainsKey i Item [Get], aby pobrać wartość ze słownika).
Jeśli uważasz, że to brzmi dziwnie, pomyśl o tym w ten sposób: Nawet jeśli obecne implementacje TryGetValue, ContainsKey i Item [Get] nie dają żadnej różnicy prędkości, możesz założyć, że prawdopodobne jest, że przyszła implementacja (np. .NET v5) zrobi (TryGetValue będzie szybszy). Pomyśl o żywotności swojego oprogramowania.
Nawiasem mówiąc, warto zauważyć, że typowe nowoczesne technologie definiowania interfejsów nadal rzadko zapewniają jakiekolwiek formalne określenie ograniczeń czasowych. Może .NET v5?
źródło
Dzięki szybkiemu programowi testowemu zdecydowanie poprawiono użycie TryGetValue z 1 milionem pozycji w słowniku.
Wyniki:
Zawiera klucz + przedmiot za 1000000 trafień: 45ms
TryGetValue dla 1000000 odsłon: 26ms
Oto aplikacja testowa:
źródło
Na mojej maszynie, z dużą ilością pamięci RAM, gdy jest uruchomiony w trybie RELEASE (nie DEBUG),
ContainsKey
jest równyTryGetValue
/try-catch
jeśli wszystkie wpisy wDictionary<>
są znalezione.ContainsKey
zdecydowanie przewyższa je wszystkie, gdy nie znaleziono tylko kilku pozycji słownika (w moim przykładzie poniżej, ustawMAXVAL
na wartość większą niż brakENTRIES
niektórych pozycji):Wyniki:
Oto mój kod:
źródło
Oprócz zaprojektowania znaku mikrodruku, który da dokładne wyniki w praktycznych warunkach, możesz sprawdzić źródło odniesienia .NET Framework.
System.Collections.Generic.Dictionary<TKey, TValue>.TryGetValue(TKey, out TValue)
System.Collections.Generic.Dictionary<TKey, TValue>.ContainsKey(TKey)
System.Collections.Generic.Dictionary<TKey, TValue>.Item(TKey)
Wszyscy nazywają
FindEntry(TKey)
metodę, która wykonuje większość pracy i nie zapamiętuje jej wyniku, więc wywołanieTryGetValue
jest prawie dwa razy szybsze niżContainsKey
+Item
.Niewygodny interfejs
TryGetValue
można dostosować za pomocą metody rozszerzenia :Od wersji C # 7.1 możesz zastąpić
default(TValue)
zwykłymdefault
. Rodzaj jest wywnioskowany.Stosowanie:
Zwraca
null
typy referencji, których wyszukiwanie kończy się niepowodzeniem, chyba że określono jawną wartość domyślną.źródło
Jeśli próbujesz wyciągnąć wartość ze słownika, TryGetValue (klucz, wartość wyjściowa) jest najlepszą opcją, ale jeśli sprawdzasz obecność klucza, czy chcesz go wstawić bez nadpisywania starych kluczy, i tylko w tym zakresie ContainsKey (klucz) jest najlepszą opcją, test porównawczy może to potwierdzić:
To jest prawdziwy przykład. Mam usługę, która dla każdego utworzonego „elementu” przypisuje numer progresywny. Numer ten, za każdym razem, gdy tworzysz nowy element, musi być znaleziony wolny, jeśli usuniesz element, bezpłatny numer stanie się za darmo, oczywiście nie jest to zoptymalizowane, ponieważ mam statyczny var, który buforuje bieżącą liczbę, ale w przypadku zakończenia wszystkich liczb, możesz ponownie rozpocząć od 0 do UInt32.MaxValue
Wykonano test:
Dodawanie elementów do
tablicy mieszającej ... Gotowe za 0,5908 - pauza ....
Dodawanie elementów do słownika ...
Gotowe za 0,2679 - pauza ....
Znajdowanie pierwszego wolnego numeru do wstawienia
Pierwsza metoda : Zawiera
klucz Gotowe w 0,0561 - wartość dodana 1000000 w słowniku - pauza ....
Druga metoda: TryGetValue
Gotowe w 0,0643 - wartość dodana 1000001 w słowniku - pauza ....
Test hashtable
Gotowe w 0, 3015 - wartość dodana 1000000 do tablicy mieszającej - pauza ....
Naciśnij dowolny klawisz, aby kontynuować. .
Jeśli niektórzy z was mogą pytać, czy klucze ContainsKeys mogą mieć przewagę, próbowałem nawet odwrócić klucz TryGetValue z kluczem Contains, wynik jest taki sam.
Więc, dla mnie, z ostatecznym rozważeniem, wszystko zależy od tego, jak program się zachowuje.
źródło