Qu'arrive-t-il à la recherche du dictionnaire C # <int, int> si la clé n'existe pas?

121

J'ai essayé de vérifier la valeur null mais le compilateur avertit que cette condition ne se produira jamais. Que dois-je rechercher?

deltanovembre
la source

Réponses:

196

En supposant que vous voulez obtenir la valeur si la clé ne sont présents, utilisez Dictionary<TKey, TValue>.TryGetValue:

int value;
if (dictionary.TryGetValue(key, out value))
{
    // Key was in dictionary; "value" contains corresponding value
} 
else 
{
    // Key wasn't in dictionary; "value" is now 0
}

(Utiliser ContainsKey, puis l'indexeur, fait chercher la clé deux fois, ce qui est assez inutile.)

Notez que même si vous étiez utilisez des types de référence, la vérification de null ne travaillerait - l'indexeur pour Dictionary<,>jetteront une exception si vous demandez une clé manquante, plutôt que de retourner nulle. (C'est une grande différence entre Dictionary<,>et Hashtable.)

Jon Skeet
la source
@JonSkeet TryGetValue ne fait-il pas également une double recherche ( comme indiqué dans ce corps de question )?
nawfal
5
@nawfal: Je ne vois aucune indication que cette question le déclare. Il dit qu'il fait plus de travail que ContainsKey, ce qui est vrai, car il doit également extraire la valeur. Cependant, il ne fait pas deux recherches.
Jon Skeet
Naïvement, j'attendais toujours null, mais pour Dictionary <TKey, enum>, cela renvoie l'équivalent "0" dans l'énumération.
Jess
23

Le dictionnaire lève une KeyNotFoundexception dans le cas où le dictionnaire ne contient pas votre clé.

Comme suggéré, ContainsKeyest la précaution appropriée. TryGetValueest également efficace.

Cela permet au dictionnaire de stocker plus efficacement une valeur de null. Sans qu'il se comporte de cette façon, la vérification d'un résultat nul de l'opérateur [] indiquerait soit une valeur nulle OU la non-existence de la clé d'entrée qui n'est pas bonne.

antik
la source
Des informations supplémentaires peuvent être trouvées sur MSDN: msdn.microsoft.com/en-gb/library/9tee9ht2.aspx
cyberzed le
10

Si vous venez de vérifier avant d'essayer d'ajouter une nouvelle valeur, utilisez la ContainsKeyméthode:

if (!openWith.ContainsKey("ht"))
{
    openWith.Add("ht", "hypertrm.exe");
}

Si vous vérifiez que la valeur existe, utilisez la TryGetValueméthode décrite dans la réponse de Jon Skeet.

ChrisF
la source
8
TryGet is better
Ruben Bartelink
2
Parce que vous résolvez la recherche de clé via la table de hachage deux fois si vous obtenez immédiatement après le contient. Wintellect PowerCollections a également des GetValueElseAddméthodes auxquelles vous donnez une valeur (ou a Func<TValue>) pour enregistrer également la résolution sur l'insert si vous allez ajouter si ce n'est pas là. Je suppose que la raison pour laquelle il n'a pas été intégré aux bibliothèques .NET est que le chemin Ajouter est moins fréquent si vous l'utilisez dans un style de cache]
Ruben Bartelink
@rub: Je suppose que cela dépend de l'objectif du code. Si vous voulez utiliser la valeur, je conviens que ce TryGetValueserait mieux, mais si vous voulez vérifier si le dictionnaire contient la clé afin d'éviter les ajouts en double, je dirais que ContainsKeyc'est tout aussi bon (sinon meilleur).
Fredrik Mörk
@Fredrik: Si vous voulez seulement faire une vérification de confinement, alors oui, cela vaut la peine d'utiliser ContainsKey. Notez que ce n'est pas le cas dans l'exemple de code de cette réponse.
Jon Skeet
@Jon: vrai, j'ai en fait manqué que la valeur ajoutée était récupérée immédiatement après son ajout.
Fredrik Mörk
3

Vous devez vérifier Dictionary.ContainsKey (clé int) avant d'essayer d'extraire la valeur.

Dictionary<int, int> myDictionary = new Dictionary<int, int>();
myDictionary.Add(2,4);
myDictionary.Add(3,5);

int keyToFind = 7;
if(myDictionary.ContainsKey(keyToFind))
{
    myValueLookup = myDictionay[keyToFind];
    // do work...
}
else
{
    // the key doesn't exist.
}
ZombieMouton
la source
2
Pourquoi voulez-vous lui faire faire la recherche deux fois?
Jon Skeet
2
@mookid: Pas à mon avis. L'idée est d'essayer de rechercher la clé et de prendre une mesure si elle est trouvée, et une autre dans le cas contraire, n'est-ce pas?
Jon Skeet
3
@Jon - Honnêtement? Parce que je ne savais pas TryGetValue. Heureusement, je le fais maintenant, donc je le saurai à l'avenir. Je vais laisser cette réponse intacte, même si la discussion est précieuse.
ZombieSheep
@Jon Skeet - C'est pourquoi je suis ici. :)
ZombieSheep
@JonSkeet Parce qu'avant C # 7, vous ne pouviez pas utiliser TryGetValuedans une expression lambda. Bien que cela me fasse penser qu'une nouvelle extension de C # serait un catchopérateur similaire à l' nullopérateur de fusion.
NetMage
1

Une classe d'assistance est pratique:

public static class DictionaryHelper
{
    public static TVal Get<TKey, TVal>(this Dictionary<TKey, TVal> dictionary, TKey key, TVal defaultVal = default(TVal))
    {
        TVal val;
        if( dictionary.TryGetValue(key, out val) )
        {
            return val;
        }
        return defaultVal;
    }
}
Sheamus
la source
Parfois, je me demande pourquoi cela n'est pas ajouté à la bibliothèque standard. Presque toutes les langues qui utilisent des hashmaps retournent null s'il n'y a pas d'entrée, pas une exception effrayante. Un élément qui n'existe pas dans votre dictionnaire n'est pas un comportement exceptionnel.
Adam Hess
@AdamHess - c'est pourquoi vous avez Hashtable () dans c # ... malheureusement, vos clés y sont
enfermées
0

ContainsKey est ce que vous recherchez.


la source
0

Vous devriez probablement utiliser:

if(myDictionary.ContainsKey(someInt))
{
  // do something
}

La raison pour laquelle vous ne pouvez pas vérifier null est que la clé ici est un type valeur.

Razzie
la source
1
Le type de la valeur est quelque peu hors de propos, car la vérification de null n'aurait pas l'effet souhaité.
Jon Skeet
@Johannes, la solution de Jon est bien sûr bien meilleure, mais le demandeur a déclaré qu'il avait vérifié si la clé existe, et c'est un Dictionary <int, int>, donc la clé est également un type valeur ici.
Razzie
0
int result= YourDictionaryName.TryGetValue(key, out int value) ? YourDictionaryName[key] : 0;

Si la clé est présente dans le dictionnaire, elle renvoie la valeur de la clé sinon elle renvoie 0.

J'espère que ce code vous aidera.

Nitika Chopra
la source
1
Si la clé existe, ce code recherchera deux fois. TryGetValuesuffit, utilisez à la valueplace deresult
Mathieu VIALES
0

Envisagez la possibilité d'encapsuler ce dictionnaire particulier et fournissez une méthode pour renvoyer la valeur de cette clé:

public static class NumbersAdapter
{
    private static readonly Dictionary<string, string> Mapping = new Dictionary<string, string>
    {
        ["1"] = "One",
        ["2"] = "Two",
        ["3"] = "Three"
    };

    public static string GetValue(string key)
    {
        return Mapping.ContainsKey(key) ? Mapping[key] : key;
    }
}

Ensuite, vous pouvez gérer le comportement de ce dictionnaire.

Par exemple ici: si le dictionnaire n'a pas la clé, il renvoie la clé que vous passez par paramètre.

pablocom96
la source