web-dev-qa-db-ja.com

.NET辞書:新規取得または新規作成

私はしばしば Dictionary を重要な値のクラス(例 List )で作成し、常に同じコードを書いていますデータを入力するときのパターン。

例えば:

var dict = new Dictionary<string, List<string>>();
string key = "foo";
string aValueForKey = "bar";

つまり、キー"bar"に対応するリストに"foo"を挿入します。ここで、キー"foo"は何にもマップされていない可能性があります。

これは私がいつも繰り返すパターンを使うところです:

List<string> keyValues;
if (!dict.TryGetValue(key, out keyValues))
  dict.Add(key, keyValues = new List<string>());
keyValues.Add(aValueForKey);

これを行うよりエレガントな方法はありますか?

この質問に対する回答がない関連質問:

39
Rok Strniša

これについては少し異なりますが、効果は同じです。

_public static TValue GetOrCreate<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key) 
    where TValue : new()
{
    TValue val;

    if (!dict.TryGetValue(key, out val))
    {
        val = new TValue();
        dict.Add(key, val);
    }

    return val;
}
_

呼ばれる:

_var dictionary = new Dictionary<string, List<int>>();

List<int> numbers = dictionary.GetOrCreate("key");
_

これは、パラメーターなしのパブリックコンストラクターwhere TValue : new()の汎用制約を利用します。

発見を助けるために、拡張メソッドが狭い問題にかなり特定されていない限り、拡張メソッドは、拡張している型の名前空間に配置する傾向があります。この場合、

_namespace System.Collections.Generic
_

ほとんどの場合、型を使用する人はusingステートメントを最初に定義しているため、IntelliSenseはコードで定義されているその拡張メソッドも見つけます。

47

非常に多くのプログラミングの問題と同様に、何かを頻繁に実行している場合は、それをメソッドにリファクタリングします。

public static void MyAdd<TKey, TCollection, TValue>(
    this Dictionary<TKey, TCollection> dictionary, TKey key, TValue value)
    where TCollection : ICollection<TValue>, new()
{
    TCollection collection;
    if (!dictionary.TryGetValue(key, out collection))
    {
        collection = new TCollection();
        dictionary.Add(key, collection);
    }
    collection.Add(value);
}
4
Servy

そして、これはどうですか?

var keyValues = dictionary[key] = dictionary.ContainsKey(key) ? dictionary[key] : new List<string>();
keyValues.Add(aValueForKey);
0
George

.Net Coreを使用する場合は、 Dictionary<>.TryAdd() を使用できます。

var dict = new Dictionary<string, string>();
dict.TryAdd("foo", "bar"); // returns bool whether it added or not feel free to ignore.
var myValue = dict["foo"];
0
Alex

OK、別のアプローチ:

public static bool TryAddValue<TKey,TValue>(this System.Collections.Generic.IDictionary<TKey,List<TValue>> dictionary, TKey key, TValue value)
    {
        // Null check (useful or not, depending on your null checking approach)
        if (value == null)
            return false;

        List<TValue> tempValue = default(List<TValue>);

        try
        {
            if (!dictionary.TryGetValue(key, out tempValue))
            {
                dictionary.Add(key, tempValue = new List<TValue>());
            }
            else
            {
                // Double null check (useful or not, depending on your null checking approach)
                if (tempValue == null)
                {
                    dictionary[key] = (tempValue = new List<TValue>());
                }
            }

            tempValue.Add(value);
            return true;
        }
        catch
        {
            return false;
        }
    }

このようにして、値をジェネリックリスト(明らかにジェネリックコレクションに一般化可能)に「追加してみて」、nullチェックを行い、ディクショナリ内の既存のキー/値を取得する必要があります。使用法と例:

var x = new Dictionary<string,List<string>>();
x.TryAddValue("test", null); // return false due to null value. Doesn't add the key
x.TryAddValue("test", "ok"); // it works adding the key/value
x.TryAddValue("test", "ok again"); // it works adding the value to the existing list

それが役に立てば幸い。

0