Różne sposoby dodawania do słownika


107

Jaka jest różnica między Dictionary.add(key, value)i Dictionary[key] = value?

Zauważyłem, że ostatnia wersja nie wyrzuca ArgumentExceptionklucza podczas wstawiania zduplikowanego klucza, ale czy jest jakiś powód, aby preferować pierwszą wersję?

Edycja : Czy ktoś ma wiarygodne źródło informacji na ten temat? Próbowałem MSDN, ale jak zwykle jest to pogoń za dziką gęś :(

Odpowiedzi:


109

Wydajność jest prawie w 100% identyczna. Możesz to sprawdzić, otwierając klasę w Reflector.net

To jest ten indeksator:

public TValue this[TKey key]
{
    get
    {
        int index = this.FindEntry(key);
        if (index >= 0)
        {
            return this.entries[index].value;
        }
        ThrowHelper.ThrowKeyNotFoundException();
        return default(TValue);
    }
    set
    {
        this.Insert(key, value, false);
    }
}

A to jest metoda Add:

public void Add(TKey key, TValue value)
{
    this.Insert(key, value, true);
}

Nie będę publikował całej metody Insert, ponieważ jest dość długa, jednak deklaracja metody jest taka:

private void Insert(TKey key, TValue value, bool add)

W dalszej części funkcji dzieje się tak:

if ((this.entries[i].hashCode == num) && this.comparer.Equals(this.entries[i].key, key))
{
    if (add)
    {
        ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate);
    }

Który sprawdza, czy klucz już istnieje, a jeśli tak, a parametr add ma wartość true, zgłasza wyjątek.

Więc dla wszystkich celów i zamiarów wydajność jest taka sama.

Podobnie jak kilka innych wzmianek, wszystko zależy od tego, czy potrzebujesz czeku, aby spróbować dwukrotnie dodać ten sam klucz.

Przepraszam za długi post, mam nadzieję, że wszystko w porządku.


+1 Bardzo interesujące, dzięki za Twój post! Wydawałoby się, że wydajność jest tutaj prawie identyczna, jak sugerowały inne plakaty, w każdym razie świetne znalezisko :)
Sune Rievers

70

Pierwsza wersja doda nową KeyValuePair do słownika, zgłaszając, czy klucz jest już w słowniku. Drugi, używając indeksatora, doda nową parę, jeśli klucz nie istnieje, ale nadpisze wartość klucza, jeśli już istnieje w słowniku.

IDictionary<string, string> strings = new Dictionary<string, string>();

strings["foo"] = "bar";          //strings["foo"] == "bar"
strings["foo"] = string.Empty;   //strings["foo"] == string.empty
strings.Add("foo", "bar");       //throws     

+1 Czy masz źródło powyższych informacji? Jestem zainteresowany dowiedzeniem się, czy są jakieś skutki uboczne lub zastrzeżenia dotyczące używania pierwszej lub drugiej formy.
Sune Rievers

3
Tak naprawdę nie mam źródła jako takiego, tuż przy mojej głowie, ale nie sądzę, aby było w nim coś więcej niż wspomniane w innych komentarzach. Jeśli dobrze pamiętam, Add po prostu używa indeksatora, ale najpierw sprawdza, czy klucz jest już używany.
hhravn

1
Zmienił zaakceptowaną odpowiedź na Steffena, ponieważ jego dokumentacja jest na najwyższym poziomie. To wciąż jest świetna odpowiedź.
Sune Rievers

@Sune: Zły ruch ... osobiście uważam, że ta odpowiedź jest o ulice przed Steffenem ... prosto do celu i przyzwoity przykład.
demoncodemonkey

1
@SuneRievers Myślę, że będzie to bardziej pomocne dla ludzi, jeśli zostanie zaakceptowana odpowiedź, zamiast obecnie zaakceptowanej odpowiedzi. Ponieważ to dokładnie odpowiada na pytanie („jaka jest różnica”), a nie zaakceptowane (mówiące o wydajności, a prawie 99% użytkowników szukających w tym temacie (jak ja), potrzebowało „różnicy” (dlaczego to spotkałem temat), a zaakceptowana odpowiedź była dla mnie bezużyteczna i marnuje naszą drugą. Zamiast tego ta odpowiedź jest dokładna.
T.Todua,

30

Dictionary.Add(key, value)i Dictionary[key] = valuemają różne cele:

  • Użyj Addmetody, aby dodać nową parę klucz / wartość, istniejące klucze nie zostaną zastąpione ( ArgumentExceptionzostanie wyrzucony).
  • Użyj indeksatora, jeśli nie obchodzi Cię, czy klucz już istnieje w słowniku, innymi słowy: dodaj parę klucz / wartość, jeśli klucza nie ma w słowniku lub zamień wartość dla określonego klucza, jeśli klucz już jest w słowniku.

1
Kod, który opisuje zamiar, jest ważny i niezwykle cenny (i nie wymaga żadnych komentarzy). Ta odpowiedź pokazuje różnicę w intencji obu metod i należy się jej kierować przy wyborze jednej. Innymi słowy, nie używaj „dodawania indeksującego”, jeśli wiesz z wyprzedzeniem , że zawsze będziesz dodawać, a nawet zawsze musisz dodawać. Zgłoszenie wyjątku IndexOutOfBounds jest lepsze niż nieoczekiwane zachowanie.
ryancdotnet

28

Aby odpowiedzieć na to pytanie, najpierw musimy przyjrzeć się celowi słownika i związanej z nim technologii.

Dictionaryto lista miejsc, w KeyValuePair<Tkey, Tvalue>których każda wartość jest reprezentowana przez swój unikalny klucz. Powiedzmy, że mamy listę Twoich ulubionych potraw. Każda wartość (nazwa potrawy) jest reprezentowana przez swój unikalny klucz (pozycja = jak bardzo lubisz to jedzenie).

Przykładowy kod:

Dictionary<int, string> myDietFavorites = new Dictionary<int, string>()
{
    { 1, "Burger"},
    { 2, "Fries"},
    { 3, "Donuts"}
};

Powiedzmy, że chcesz zachować zdrowie, zmieniłeś zdanie i chcesz zastąpić swojego ulubionego „burgera” sałatką. Twoja lista jest nadal listą ulubionych, nie zmienisz charakteru listy. Twój ulubiony pozostanie numerem jeden na liście, tylko jego wartość ulegnie zmianie. To wtedy nazywasz to:

/*your key stays 1, you only replace the value assigned to this key
  you alter existing record in your dictionary*/
myDietFavorites[1] = "Salad";

Ale nie zapominaj, że jesteś programistą i od teraz kończysz swoje zdania; odmawiasz używania emoji, ponieważ zgłaszałyby one błąd kompilacji, a cała lista ulubionych jest oparta na indeksie 0.

Twoja dieta też się zmieniła! Więc ponownie zmieniasz listę:

/*you don't want to replace Salad, you want to add this new fancy 0
  position to your list. It wasn't there before so you can either define it*/
myDietFavorites[0] = "Pizza";

/*or Add it*/
myDietFavorites.Add(0, "Pizza");

Istnieją dwie możliwości definiowania: albo chcesz podać nową definicję czegoś, co wcześniej nie istniało, albo chcesz zmienić definicję, która już istnieje.

Add umożliwia dodanie rekordu, ale tylko pod jednym warunkiem: klucz dla tej definicji może nie istnieć w Twoim słowniku.

Teraz zajrzymy pod maskę. Kiedy tworzysz słownik, twój kompilator dokonuje rezerwacji dla zasobnika (spacje w pamięci do przechowywania twoich rekordów). Zasobnik nie przechowuje kluczy w sposób, w jaki je definiujesz. Każdy klucz jest haszowany przed przejściem do zasobnika (zdefiniowanego przez Microsoft), warto wspomnieć, że część wartości pozostaje niezmieniona.

Użyję algorytmu mieszania CRC32, aby uprościć mój przykład. Podczas definiowania:

myDietFavorites[0] = "Pizza";

Do wiadra trafia db2dc565 „Pizza” (uproszczona).

Gdy zmienisz wartość w:

myDietFavorites[0] = "Spaghetti";

Haszujesz swoje 0, które ponownie jest db2dc565, a następnie sprawdzasz tę wartość w swoim zasobniku , aby sprawdzić, czy tam jest. Jeśli tam jest, po prostu przepisujesz wartość przypisaną do klucza. Jeśli go tam nie ma, umieścisz swoją wartość w wiadrze.

Podczas wywoływania funkcji Dodaj w słowniku, na przykład:

myDietFavorite.Add(0, "Chocolate");

Haszujesz swoje 0, aby porównać jego wartość z wartościami w zasobniku. Możesz umieścić go w wiadrze tylko wtedy, gdy go tam nie ma .

Ważne jest, aby wiedzieć, jak to działa, zwłaszcza jeśli pracujesz ze słownikami kluczy typu string lub char. W związku z haszowaniem rozróżniana jest wielkość liter. Na przykład „imię”! = „Imię”. Użyjmy naszego CRC32, aby to zobrazować.

Wartość dla „nazwy” to: e04112b1 Wartość dla „nazwy” to: 1107fb5b


Te dwie linie wystarczą, aby zrozumieć ....... Istnieją dwie możliwości definiowania: albo chcesz podać nową definicję czegoś, co wcześniej nie istniało, albo chcesz zmienić definicję, która już istnieje. Add umożliwia dodanie rekordu, ale tylko pod jednym warunkiem: klucz dla tej definicji może nie istnieć w Twoim słowniku.
Niraj Trivedi

4

Tak, na tym polega różnica, metoda Add zgłasza wyjątek, jeśli klucz już istnieje.

Powód użycia metody Add jest dokładnie taki. Jeśli słownik nie powinien już zawierać klucza, zwykle potrzebujesz wyjątku, abyś był świadomy problemu.


0

Biorąc pod uwagę najbardziej prawdopodobne podobieństwa w wydajności, użyj tego, co wydaje się bardziej poprawne i czytelne dla używanego fragmentu kodu.

Wydaje mi się, że operacja opisująca dodatek, będąca obecnością klucza, który jest już naprawdę rzadkim wyjątkiem, najlepiej reprezentuje dodatek. Semantycznie ma to większy sens.

dict[key] = valueOznacza lepsze zmiany. Jeśli widzę ten kod, w połowie spodziewam się, że klucz i tak jest już w słowniku.


Zakładam, że brak sprawdzenia, czy klucz istnieje jako pierwszy, daje niewielki wzrost wydajności. Nie spodziewałbym się po dic[key] = valuetym, że klucz był już obecny, ale myślę, że to dyskusyjne;)
Sune Rievers

2
+ Myślę, że rzucanie nigdy nie powinno być używane jako sposób sprawdzenia, czy klucz jest już reprezentowany. if (! strings.ContainsKey ("foo")) strings.Add ("foo", "bar");
hhravn


0

Aby wstawić wartość do słownika

 Dictionary<string, string> dDS1 = new Dictionary<string, string>();//Declaration
 dDS1.Add("VEqpt", "aaaa");//adding key and value into the dictionary
 string Count = dDS1["VEqpt"];//assigning the value of dictionary key to Count variable
 dDS1["VEqpt"] = Count + "bbbb";//assigning the value to key
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.