web-dev-qa-db-fra.com

Différentes façons d’ajouter au dictionnaire

Quelle est la différence entre Dictionary.add(key, value) et Dictionary[key] = value?

J'ai remarqué que la dernière version ne jette pas un ArgumentException lors de l'insertion d'une clé dupliquée, mais y a-t-il une raison de préférer la première version?

Edit: Quelqu'un at-il une source d’information faisant autorité à ce sujet? J'ai essayé MSDN, mais c'est comme toujours une chasse à l'oie sauvage :(

91
Sune Rievers

La performance est presque identique à 100%. Vous pouvez vérifier cela en ouvrant la classe dans Reflector.net

C'est l'indexeur This:

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);
    }
}

Et voici la méthode Add:

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

Je ne publierai pas l'intégralité de la méthode Insert car elle est plutôt longue. Cependant, la déclaration de la méthode est la suivante:

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

Et plus bas dans la fonction, cela se produit:

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

Qui vérifie si la clé existe déjà, et si c'est le cas et que le paramètre add est true, il lève l'exception.

Donc, pour tous les buts et les intentions, la performance est la même.

Comme quelques autres mentions, tout est question de savoir si vous avez besoin de vérifier ou d’essayer d’ajouter deux fois la même clé.

Désolé pour le long post, j'espère que ça va.

98
Steffen

La première version ajoutera un nouveau KeyValuePair au dictionnaire, en lançant si la clé est déjà dans le dictionnaire. La seconde, en utilisant l'indexeur, ajoutera une nouvelle paire si la clé n'existe pas, mais remplacera la valeur de la clé si elle existe déjà dans le dictionnaire.

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     
67
hhravn

Dictionary.Add(key, value) et Dictionary[key] = value ont des objectifs différents:

  • Utilisez la méthode Add pour ajouter nouvelle paire clé/valeur, les clés existantes ne seront pas remplacées (un ArgumentException est levé).
  • Utilisez l'indexeur si la clé existe déjà dans le dictionnaire, c'est-à-dire: ajoutez la paire clé/valeur si la clé ne figure pas dans le dictionnaire ou remplacez la valeur de la clé spécifiée si la clé est déjà dans le dictionnaire.
29
Michael Damatov

Pour répondre d'abord à la question, nous devons examiner le but d'un dictionnaire et de la technologie sous-jacente.

Dictionary est la liste de KeyValuePair<Tkey, Tvalue> où chaque valeur est représentée par sa clé unique. Disons que nous avons une liste de vos aliments préférés. Chaque valeur (nom de l'aliment) est représentée par sa clé unique (une position = combien vous aimez cet aliment).

Exemple de code:

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

Disons que vous voulez rester en bonne santé, que vous avez changé d'avis et que vous voulez remplacer votre "Burger" préféré par une salade. Votre liste est toujours une liste de vos favoris, vous ne changerez pas la nature de la liste. Votre favori restera numéro un sur la liste, seule sa valeur changera. C'est à ce moment-là que vous appelez ceci:

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

Mais n'oubliez pas que vous êtes le programmeur et que vous finissez désormais vos phrases avec; vous refusez d’utiliser des émoticônes car ils jetteraient une erreur de compilation et toute la liste des favoris est basée sur un index 0.

Votre régime a aussi changé! Donc, vous modifiez à nouveau votre liste:

/*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");

Il y a deux possibilités avec la définition, soit vous voulez donner une nouvelle définition pour quelque chose qui n'existe pas auparavant, soit vous voulez changer la définition qui existe déjà.

La méthode d'ajout vous permet d'ajouter un enregistrement, mais seulement sous une condition: la clé pour cette définition peut ne pas exister dans votre dictionnaire.

Maintenant, nous allons regarder sous le capot. Lorsque vous créez un dictionnaire, votre compilateur fait une réservation pour le compartiment (espaces en mémoire pour stocker vos enregistrements). Bucket ne stocke pas les clés de la manière que vous les définissez. Chaque clé est hachée avant d’aller dans le compartiment (défini par Microsoft), il est à noter que la partie de valeur reste inchangée.

J'utiliserai l'algorithme de hachage CRC32 pour simplifier mon exemple. Lorsque vous définissez:

myDietFavorites[0] = "Pizza";

Ce qui se passe dans le compartiment est db2dc565 "Pizza" (simplifié).

Lorsque vous modifiez la valeur dans avec:

myDietFavorites[0] = "Spaghetti";

Vous hachez votre 0 qui est encore db2dc565 alors vous recherchez cette valeur dans votre compartiment pour trouver si elle est là. Si c'est le cas, il vous suffit de réécrire la valeur attribuée à la clé. Si ce n'est pas là, vous placerez votre valeur dans le seau.

Lorsque vous appelez Ajouter une fonction sur votre dictionnaire comme:

myDietFavorite.Add(0, "Chocolate");

Vous hachez votre 0 pour comparer sa valeur à celles du panier. Vous pouvez le placer dans le seau seulement si ce n’est pas là.

Il est essentiel de savoir comment cela fonctionne, surtout si vous utilisez des dictionnaires de type chaîne ou caractère. Il est sensible à la casse en raison du hachage en cours. Donc, par exemple "name"! = "Name". Utilisons notre CRC32 pour illustrer cela.

La valeur pour "nom" est: e04112b1 La valeur pour "nom" est: 1107fb5b

22
Kamil Kurzynowski

Oui, c'est la différence. La méthode Add lève une exception si la clé existe déjà.

La raison d'utiliser la méthode Add est exactement celle-ci. Si le dictionnaire n'est pas censé contenir déjà la clé, vous souhaitez généralement l'exception afin de vous informer du problème.

4
Guffa

Étant donné les similitudes, plus que probables, de performances, utilisez ce qui vous semble le plus correct et lisible pour le code que vous utilisez.

Je pense qu'une opération qui décrit un ajout, étant la présence de la clé, une exception déjà très rare est mieux représentée avec l'addition. Sémantiquement, cela a plus de sens.

Le dict[key] = value représente mieux une substitution. Si je vois ce code, je m'attends presque à ce que la clé soit déjà dans le dictionnaire.

0
Jorge Córdoba

L'un attribue une valeur tandis que l'autre ajoute au dictionnaire une nouvelle clé et une nouvelle valeur.

0
Joshua Smith