キーが存在しない場合、C#Dictionary <int、int>ルックアップはどうなりますか?


121

nullをチェックしようとしましたが、コンパイラーはこの状態が発生しないことを警告しています。何を探すべきですか?

回答:


196

キー存在する場合に値を取得する場合は、次を使用します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
}

ContainsKeyインデクサーを使用してから、キーを2回調べます。これはかなり無意味です。)

参照型使用している場合でも、nullのチェックは機能しません。nullをDictionary<,>返すのではなく、不足しているキーを要求すると、インデクサーは例外をスローします。(これは大きな違いであるDictionary<,>Hashtable。)


@JonSkeet(この質問の本文に記載されているように)TryGetValueも二重検索を行っていませんか?
nawfal

5
@nawfal:その質問がそれを述べていることを示す兆候はまったくありません。ContainsKey値よりも抽出しなければならないため、それは真よりも多くの仕事をしていると言います。ただし、2つのルックアップは行いません。
Jon Skeet

単純に、私はnullを期待し続けましたが、Dictionary <TKey、enum>の場合、これはenumで同等の「0」を返します。
Jess

23

辞書にKeyNotFoundキーが含まれていない場合、辞書は例外をスローします。

提案されているようにContainsKey、適切な予防策です。 TryGetValueも効果的です。

これにより、ディクショナリはnullの値をより効果的に格納できます。このように動作しない場合、[]演算子からのnull結果をチェックすると、null値か、入力キーが存在しないために問題があります。


追加情報はMSDNにあります: msdn.microsoft.com/en-gb/library/9tee9ht2.aspx
cyberzed

10

新しい値を追加する前に確認するだけの場合は、次のContainsKeyメソッドを使用します。

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

値が存在することを確認する場合TryGetValueは、Jon Skeetの回答に記載されている方法を使用します。


8
TryGetの方が優れている
Ruben Bartelink

2
含むの直後に取得した場合、ハッシュテーブルを介してキー検索を2回解決していることになります。Wintellect PowerCollectionsにはGetValueElseAdd、値(またはFunc<TValue>)を指定してInsertの解像度を保存するメソッドもあり、そこに追加しない場合は追加します。.NETライブラリに組み込まれなかった理由は、キャッシュスタイルで追加パスを使用すると、追加パスの頻度が低くなるためです]
Ruben Bartelink

@rub:コードの目的に依存すると思います。あなたが私が同意する値を使用したい場合はTryGetValueより良いでしょうが、重複した追加を避けるためにディクショナリにキーが含まれているかどうかを確認したい場合、私ContainsKeyは同じように良いと思います(良くない場合)。
FredrikMörk、2010年

@Fredrik:包含チェックのみを行いたい場合は、はい、ContainsKeyを使用する価値があります。この回答のサンプルコードではそうではないことに注意してください。
Jon Skeet、2010年

@ジョン:真、私は実際に、追加された値が追加された直後にフェッチされることを逃しました。
FredrikMörk、2010年

3

値を取得する前に、Dictionary.ContainsKey(int key)を確認する必要があります。

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

2
なぜ2度検索を行わせたいのですか?
Jon Skeet、2010年

2
@mookid:私の意見ではありません。アイデアは、キーを調べて、見つかった場合は1つのアクションコースを実行し、それ以外の場合は別のアクションコースを実行することです。
Jon Skeet、2010年

3
@ジョン-正直なところ?知らなかったからTryGetValue。ありがたいことに、私は今、そうしているので、将来知っています。この回答はそのままにしておきますが、 'cosの議論は価値があります。
ZombieSheep

@ジョンスキート-それが私がここにいる理由です。:)
ZombieSheep

@JonSkeet C#7より前のバージョンTryGetValueでは、ラムダ式では使用できませんでした。それでも、C#の新しい拡張機能catchは、null合体演算子に似た演算子になると思います。
NetMage 2017

1

ヘルパークラスは便利です。

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

なぜこれが標準ライブラリに追加されないのか不思議に思うことがあります。ハッシュマップを使用するほとんどすべての言語は、エントリがない場合、異常な例外ではない場合、nullを返します。辞書に存在しないアイテムは例外的な動作ではありません。
Adam Hess

@AdamHess-C#にHashtable()があるのはそのためです...残念ながら、キーはそこでボックス化されます... :(
veljkoz


0

あなたはおそらく使うべきです:

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

nullを確認できないのは、ここのキーが値型であるためです。


1
nullのチェックは望ましい効果をもたらさないため、値のタイプはいくぶん無関係です。
Jon Skeet、2010年

@Johannes、ジョンのソリューションはもちろんはるかに優れていますが、質問者はキーが存在するかどうかを確認し、それがDictionary <int、int>であるため、キーもここでは値の型であると述べました。
Razzie、2010年

0
int result= YourDictionaryName.TryGetValue(key, out int value) ? YourDictionaryName[key] : 0;

キーがディクショナリに存在する場合は、キーの値を返し、それ以外の場合は0を返します。

このコードがお役に立てば幸いです。


1
キーが存在する場合、このコードは2回ルックアップします。 代わりにTryGetValue使用してくださいvalueresult
Mathieu VIALES

0

この特定の辞書をカプセル化するオプションを検討し、そのキーの値を返すメソッドを提供します。

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

その後、この辞書の動作を管理できます。

たとえば、次の例のように、辞書にキーがない場合は、パラメータで渡したキーを返します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.