Différentes façons d'ajouter au dictionnaire


107

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

J'ai remarqué que la dernière version ne lance pas de message ArgumentExceptionlors de l'insertion d'une clé en double, mais y a-t-il une raison de préférer la première version?

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

Réponses:


109

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 toute la méthode Insert car elle est plutôt longue, mais 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);
    }

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

Donc, à toutes fins et intentions, la performance est la même.

Comme quelques autres mentions, il s'agit de savoir si vous avez besoin de la vérification, pour les tentatives d'ajout de la même clé deux fois.

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


+1 Très intéressant, merci pour votre message! Il semblerait que les performances soient presque identiques ici, comme l'ont laissé entendre les autres affiches, en tout cas une bonne trouvaille :)
Sune Rievers

70

La première version ajoutera un nouveau KeyValuePair au dictionnaire, jetant si la clé est déjà dans le dictionnaire. Le second, en utilisant l'indexeur, ajoutera une nouvelle paire si la clé n'existe pas, mais écrasera 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     

+1 Avez-vous une source pour les informations ci-dessus? Je suis intéressé à savoir s'il y a des effets secondaires ou des mises en garde à utiliser la première ou la dernière forme.
Sune Rievers

3
Je n'ai pas vraiment de source en tant que telle, juste au-dessus de ma tête, mais je ne pense pas qu'il y ait beaucoup plus que ce qui est mentionné dans les autres commentaires. Si je me souviens bien, Add utilise simplement l'indexeur, mais vérifie d'abord si la clé est déjà utilisée.
hhravn

1
Changement de réponse acceptée à celle de Steffen, car sa documentation est de premier ordre. C'est toujours une excellente réponse.
Sune Rievers

@Sune: Mauvais mouvement ... personnellement, je pense que cette réponse est en avance sur celle de Steffen ... droit au but et un exemple décent.
demoncodemonkey

1
@SuneRievers Je pense que ce sera plus utile pour les gens, si la réponse est acceptée pour cela, au lieu de la réponse acceptée actuelle. Parce que cela répond exactement à la question ("quelle est la différence"), plutôt qu'à la question acceptée (qui parle de performances, et près de 99% des utilisateurs recherchant ce sujet (comme moi), avaient besoin de la "différence" (pourquoi j'ai rencontré cela sujet), et la réponse acceptée était inutile pour moi et les déchets de notre deuxième place, cette réponse est exacte..
T.Todua

30

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

  • Utilisez la Addméthode pour ajouter une nouvelle paire clé / valeur, les clés existantes ne seront pas remplacées (un ArgumentExceptionest lancé).
  • Utilisez l'indexeur si vous ne vous souciez pas de savoir si la clé existe déjà dans le dictionnaire, en d'autres termes: ajoutez la paire clé / valeur si la clé n'est pas dans le dictionnaire ou remplacez la valeur de la clé spécifiée si la clé est déjà dans le dictionnaire.

1
Un code qui auto-décrit l'intention est important et extrêmement précieux (et nécessite peu ou pas de commentaires). Cette réponse montre la différence d'intention avec les deux méthodes et doit être suivie lors du choix d'une. En d'autres termes, n'utilisez pas le 'indexer add' lorsque vous savez à l'avance que vous allez toujours ajouter, ou même que vous devez toujours ajouter. La levée d'une exception IndexOutOfBounds est préférable à un comportement inattendu.
ryancdotnet

28

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

Dictionaryest la liste 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 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 à partir de maintenant vous finissez vos phrases avec; vous refusez d'utiliser des emojis car ils généreraient une erreur de compilation et toute la liste des favoris est basée sur un index 0.

Votre alimentation a également changé! Vous modifiez donc à 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'existait pas auparavant, soit vous voulez changer la définition qui existe déjà.

La méthode Add vous permet d'ajouter un enregistrement mais à une seule condition: la clé de 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 effectue une réservation pour le bucket (espaces en mémoire pour stocker vos enregistrements). Le bucket ne stocke pas les clés de la manière dont vous les définissez. Chaque clé est hachée avant d'aller dans le compartiment (défini par Microsoft), il convient de mentionner que la partie valeur reste inchangée.

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

myDietFavorites[0] = "Pizza";

Ce qui va dans le seau est db2dc565 "Pizza" (simplifié).

Lorsque vous modifiez la valeur avec:

myDietFavorites[0] = "Spaghetti";

Vous hachez votre 0 qui est à nouveau db2dc565 puis vous recherchez cette valeur dans votre bucket pour savoir si elle est là. Si c'est là, vous réécrivez simplement la valeur assignée à la clé. Si ce n'est pas là, vous placerez votre valeur dans le seau.

Lorsque vous appelez la fonction Ajouter sur votre dictionnaire comme:

myDietFavorite.Add(0, "Chocolate");

Vous hachez votre 0 pour comparer sa valeur à celles du compartiment. Vous ne pouvez le placer dans le seau que s'il n'y est pas .

Il est crucial de savoir comment cela fonctionne, surtout si vous travaillez avec des dictionnaires de clé de type chaîne ou char. Il est sensible à la casse en raison du hachage. Donc par exemple "nom"! = "Nom". Utilisons notre CRC32 pour illustrer cela.

La valeur de «nom» est: e04112b1 La valeur de «nom» est: 1107fb5b


Ces deux lignes suffisent pour comprendre ....... Il y a deux possibilités avec la définition, soit vous voulez donner une nouvelle définition pour quelque chose qui n'existait pas auparavant, soit vous voulez changer la définition qui existe déjà. La méthode Add vous permet d'ajouter un enregistrement mais à une seule condition: la clé de cette définition peut ne pas exister dans votre dictionnaire.
Niraj Trivedi

4

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 la suivante. Si le dictionnaire n'est pas censé contenir déjà la clé, vous voulez généralement l'exception pour que vous soyez informé du problème.


0

Compte tenu des similitudes les plus probables en termes de performances, utilisez ce qui vous semble le plus correct et lisible pour le morceau de code que vous utilisez.

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

Le dict[key] = valuereprésente mieux une substitution. Si je vois ce code, je m'attends à moitié que la clé soit déjà dans le dictionnaire de toute façon.


Je suppose qu'il y a un petit gain de performances à ne pas vérifier si la clé existe en premier. Je ne m'attendrais pas à ce dic[key] = valueque la clé soit déjà présente, mais je suppose que c'est discutable;)
Sune Rievers

2
+ Je pense que le lancer ne devrait jamais être utilisé pour vérifier si la clé est déjà représentée. if (! strings.ContainsKey ("foo")) strings.Add ("foo", "bar");
hhravn

0

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


0

Pour insérer la valeur dans le dictionnaire

 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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.