Was passiert mit der Suche nach C # Dictionary <int, int>, wenn der Schlüssel nicht vorhanden ist?

121

Ich habe versucht, nach null zu suchen, aber der Compiler warnt davor, dass diese Bedingung niemals auftreten wird. Was soll ich suchen?

deltanovember
quelle

Antworten:

196

Vorausgesetzt , dass Sie den Wert erhalten möchten , wenn der Schlüssel tut vorhanden ist , verwenden 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
}

(Wenn Sie ContainsKeyden Indexer verwenden und dann den Indexer verwenden, wird der Schlüssel zweimal nachgeschlagen, was ziemlich sinnlos ist.)

Beachten Sie, dass , auch wenn Sie wurden Referenztypen verwenden, für null Überprüfung nicht funktionieren würde - der Indexer für Dictionary<,>eine Exception aus , wenn Sie einen fehlenden Schlüssel anfordern, anstatt null zurück. (Dies ist ein großer Unterschied zwischen Dictionary<,>und Hashtable.)

Jon Skeet
quelle
@ JonSkeet Führt TryGetValue nicht auch eine doppelte Suche durch ( wie in diesem Fragetext angegeben )?
Nawfal
5
@nawfal: Ich sehe keinen Hinweis darauf, dass diese Frage das überhaupt besagt. Es heißt, es macht mehr Arbeit als ContainsKey, was wahr ist, weil es auch den Wert extrahieren muss. Es werden jedoch nicht zwei Suchvorgänge durchgeführt.
Jon Skeet
Naiv habe ich immer wieder Null erwartet, aber für Dictionary <TKey, enum> gibt dies das "0" -Äquivalent in der Aufzählung zurück.
Jess
23

Das KeyNotFoundWörterbuch löst eine Ausnahme aus, falls das Wörterbuch Ihren Schlüssel nicht enthält.

Wie vorgeschlagen, ContainsKeyist die entsprechende Vorsichtsmaßnahme. TryGetValueist auch wirksam.

Dadurch kann das Wörterbuch den Wert null effektiver speichern. Ohne dieses Verhalten würde die Überprüfung auf ein Null-Ergebnis durch den Operator [] entweder einen Nullwert oder die Nichtexistenz des Eingabeschlüssels anzeigen, was nicht gut ist.

antik
quelle
Weitere Informationen finden Sie unter MSDN: msdn.microsoft.com/en-gb/library/9tee9ht2.aspx
Cyberzed
10

Wenn Sie nur prüfen, bevor Sie versuchen, einen neuen Wert hinzuzufügen, verwenden Sie die folgende ContainsKeyMethode:

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

Wenn Sie überprüfen, ob der Wert vorhanden ist, verwenden Sie die TryGetValuein der Antwort von Jon Skeet beschriebene Methode.

ChrisF
quelle
8
TryGet ist besser
Ruben Bartelink
2
Weil Sie die Schlüsselsuche zweimal über die Hashtabelle auflösen, wenn Sie sofort nach den Contains suchen. Wintellect PowerCollections verfügt auch über GetValueElseAddMethoden, mit denen Sie einen Wert (oder a Func<TValue>) angeben, um auch die Auflösung beim Einfügen zu speichern, wenn Sie hinzufügen möchten , wenn diese nicht vorhanden ist. Ich denke, der Grund, warum es nicht in die .NET-Bibliotheken geschafft hat, ist, dass der Add-Pfad weniger häufig ist, wenn Sie ihn in einem Cache-Stil verwenden.]
Ruben Bartelink
@rub: Ich denke, das hängt vom Zweck des Codes ab. Wenn Sie den Wert verwenden möchten, stimme ich zu, dass TryGetValuedies besser wäre, aber wenn Sie überprüfen möchten, ob das Wörterbuch den Schlüssel enthält, um doppelte Ergänzungen zu vermeiden, würde ich sagen, dass dies ContainsKeygenauso gut ist (wenn nicht besser).
Fredrik Mörk
@Fredrik: Wenn Sie nur eine Eindämmungsprüfung durchführen möchten, lohnt es sich, ContainsKey zu verwenden. Beachten Sie, dass dies im Beispielcode dieser Antwort nicht der Fall ist.
Jon Skeet
@ Jon: stimmt, ich habe tatsächlich übersehen, dass der Mehrwert sofort nach dem Hinzufügen abgerufen wurde.
Fredrik Mörk
3

Sie sollten nach Dictionary.ContainsKey (int key) suchen, bevor Sie versuchen, den Wert abzurufen.

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.
}
ZombieSheep
quelle
2
Warum soll die Suche zweimal durchgeführt werden?
Jon Skeet
2
@mookid: Meiner Meinung nach nicht. Die Idee ist, zu versuchen, den Schlüssel nachzuschlagen und eine Vorgehensweise zu ergreifen, wenn er gefunden wurde, und eine andere Vorgehensweise, oder?
Jon Skeet
3
@ Jon - Ehrlich? Weil ich nichts davon wusste TryGetValue. Zum Glück mache ich das jetzt, also werde ich es in Zukunft wissen. Ich werde diese Antwort intakt lassen, obwohl die Diskussion wertvoll ist.
ZombieSheep
@ Jon Skeet - Deshalb bin ich hier. :)
ZombieSheep
@ JonSkeet Weil Sie vor C # 7 keinen TryGetValueLambda-Ausdruck verwenden konnten. Das lässt mich jedoch denken, dass eine neue Erweiterung von C # ein catchOperator wäre , der dem nullKoaleszenzoperator ähnlich ist .
NetMage
1

Eine Helferklasse ist praktisch:

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
quelle
Manchmal frage ich mich, warum dies nicht zur Standardbibliothek hinzugefügt wird. Fast alle Sprachen, die Hashmaps verwenden, geben null zurück, wenn es keinen Eintrag gibt, keine verdammte Ausnahme. Ein Element, das nicht in Ihrem Wörterbuch vorhanden ist, ist kein außergewöhnliches Verhalten.
Adam Hess
@AdamHess - deshalb haben Sie Hashtable () in c # ... leider werden Ihre Schlüssel dort verpackt ... :(
veljkoz
0

ContainsKey ist das, wonach Sie suchen.


quelle
0

Sie sollten wahrscheinlich verwenden:

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

Der Grund, warum Sie nicht nach null suchen können, ist, dass der Schlüssel hier ein Werttyp ist.

Razzie
quelle
1
Der Typ des Werts ist etwas irrelevant, da die Überprüfung auf Null nicht den gewünschten Effekt hätte.
Jon Skeet
@Johannes, Jons Lösung ist natürlich viel besser, aber der Fragesteller hat angegeben, dass er überprüft hat, ob der Schlüssel vorhanden ist, und es ist ein Wörterbuch <int, int>, sodass der Schlüssel hier auch ein Werttyp ist.
Razzie
0
int result= YourDictionaryName.TryGetValue(key, out int value) ? YourDictionaryName[key] : 0;

Wenn der Schlüssel im Wörterbuch vorhanden ist, gibt er den Wert des Schlüssels zurück, andernfalls wird 0 zurückgegeben.

Hoffe, dieser Code hilft dir.

Nitika Chopra
quelle
1
Wenn der Schlüssel vorhanden ist, wird dieser Code zweimal nachgeschlagen. TryGetValueist genug, verwenden Sie valueanstelle vonresult
Mathieu VIALES
0

Ziehen Sie die Option in Betracht, dieses bestimmte Wörterbuch zu kapseln, und stellen Sie eine Methode bereit, um den Wert für diesen Schlüssel zurückzugeben:

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

Dann können Sie das Verhalten dieses Wörterbuchs verwalten.

Zum Beispiel hier: Wenn das Wörterbuch nicht über den Schlüssel verfügt, gibt es den Schlüssel zurück, den Sie als Parameter übergeben.

pablocom96
quelle