Pobieranie najlepszych praktyk dotyczących wartości słownikowych

79

Niedawno zauważyłem Dictionary.TryGetValue(TKey key, out TValue value)i byłem ciekawy, które jest lepsze podejście do pobierania wartości ze słownika.

Tradycyjnie robiłem:

if (myDict.Contains(someKey))
     someVal = myDict[someKey];
     ...

chyba że wiem, że musi tam być.

Czy lepiej po prostu zrobić:

if (myDict.TryGetValue(somekey, out someVal)
    ...

Która praktyka jest lepsza? Czy jeden jest szybszy od drugiego? Wyobrażam sobie, że wersja Try byłaby wolniejsza, ponieważ „połyka” próbę / haczyk wewnątrz siebie i używa jej jako logiki, nie?

Nicholas Mancuso
źródło

Odpowiedzi:

84

TryGetValue jest nieco szybsze, ponieważ FindEntry zostanie wywołane tylko raz.

O ile szybciej? To zależy od posiadanego zbioru danych. Po wywołaniu metody Contains Dictionary przeprowadza wewnętrzne wyszukiwanie w celu znalezienia indeksu. Jeśli zwróci wartość true, potrzebujesz kolejnego przeszukania indeksu, aby uzyskać rzeczywistą wartość. Gdy używasz TryGetValue, przeszukuje indeks tylko raz, a jeśli zostanie znaleziony, przypisuje wartość do zmiennej.

FYI: Tak naprawdę to nie wyłapuje błąd.

Woła:

public bool TryGetValue(TKey key, out TValue value)
{
    int index = this.FindEntry(key);
    if (index >= 0)
    {
        value = this.entries[index].value;
        return true;
    }
    value = default(TValue);
    return false;
}

ContainsKey to:

public bool ContainsKey(TKey key)
{
    return (this.FindEntry(key) >= 0);
}
Micheasza
źródło
TryGetValue jest nieco szybsze, ponieważ FindEntry zostanie wywołane tylko raz.
Joe
1
TryGetValue jest znacznie szybsze, gdy masz duży słownik
Diadistis,
4
Teoretycznie (cóż, również w praktyce) nie powinno to zależeć od rozmiaru słownika, ponieważ oczekiwany (!) Czas pobierania jest stały, tj. Niezależny od rozmiaru słownika!
Konrad Rudolph,
29

W rzeczywistości TryGetValue jest szybsze. O ile szybciej? To zależy od posiadanego zbioru danych. Po wywołaniu metody Contains Dictionary przeprowadza wewnętrzne wyszukiwanie w celu znalezienia indeksu. Jeśli zwróci wartość true, potrzebujesz kolejnego przeszukania indeksu, aby uzyskać rzeczywistą wartość. Gdy używasz TryGetValue, przeszukuje indeks tylko raz, a jeśli zostanie znaleziony, przypisuje wartość do zmiennej.

Edytować:

Ok, rozumiem twoje zamieszanie, więc pozwól mi rozwinąć:

Przypadek 1:

if (myDict.Contains(someKey))
     someVal = myDict[someKey];

W tym przypadku istnieją 2 wywołania funkcji FindEntry, jedno w celu sprawdzenia, czy klucz istnieje i jedno w celu jego odzyskania

Przypadek 2:

myDict.TryGetValue(somekey, out someVal)

W tym przypadku istnieje tylko jedno wywołanie FindKey, ponieważ wynikowy indeks jest przechowywany do faktycznego pobierania w tej samej metodzie.

Diadistis
źródło
Zgoda. TryGetValue eliminuje potrzebę dwukrotnego wyszukiwania klucza. Może też pomóc w przypadku wielowątkowości. Od czasu sprawdzania, czy wartość istnieje, mogła zostać dodana lub usunięta. Może to powodować wyjątki „klucz już istnieje” lub „Nie znaleziono klucza”.
Brian Rudolph,
0

Wyobrażam sobie, że trygetvalue robi coś bardziej jak:

if(myDict.ReallyOptimisedVersionofContains(someKey))
{ 
  someVal = myDict[someKey];
  return true;
}
return false;

Miejmy nadzieję, że nigdzie nie próbuj / łapaj.

Myślę, że to naprawdę wygodna metoda. Generalnie używam go, ponieważ zapisuje jeden lub dwa wiersze kodu.

Jennifer
źródło