2014-11-06 105 views
0

有沒有一種簡單的方法來爲嵌套字典添加值。我正在尋找一種方法來取代以下類型的代碼。C#簡單的方法來添加鍵和值嵌套字典?

if (NestedDictionary.ContainsKey(key1)) 
{ 
    if (NestedDictionary[key1].ContainsKey(key2)) 
    { 
     if (NestedDictionary[key1][key2].ContainsKey(key3)) 
     { 
      //do nothing 
     } 
     else 
     { 
      NestedDictionary[key1][key2].Add(key3,1); 

     } 
    } 
    else 
    { 

     NestedDictionary[key1].Add(key2, new Dictionary<int,int>() { { key3, 1 } }); 
    } 
} 
else 
{ 
    NestedDictionary.Add(key1, new Dictionary<int, Dictionary<int,int>>() { { key2, new Dictionary<int,int>() { { key3, 1} } } }); 
} 
+3

在我看來,你需要一個更好定義的對象來管理這些數據... – jaywayco 2014-11-06 20:46:53

+2

程序員有時會編寫類。 – Stilgar 2014-11-06 20:47:22

+0

與帶有key1,key2,key3組合的字典不一樣嗎? – 2014-11-06 20:52:53

回答

0

可以簡化內部:

if (NestedDictionary.ContainsKey(key1)) 
{ 
    if (NestedDictionary[key1].ContainsKey(key2)) 
    { 
     NestedDictionary[key1][key2][key3]=1; 
    } 
    else 
    { 
     NestedDictionary[key1].Add(key2, new Dictionary<int,int>() { { key3, 1 } }); 
    } 
} 
else 
{ 
    NestedDictionary.Add(key1, new Dictionary<int, Dictionary<int,int>>() { { key2, new Dictionary<int,int>() { { key3, 1} } } }); 
} 

但僅此而已。

但是結構的要點是什麼?你只會向最裏面的字典中添加一個常量值(1),所以沒有真正的「價值」。您不妨在該級別使用List<string>

3

我們可以寫一個GetOrAdd方法,要麼得到值特定關鍵,如果它的存在,或者如果沒有,則分配一個新值:

public static TValue GetOrAdd<TKey, TValue>(
    this Dictionary<TKey, TValue> dictionary, 
    TKey key, 
    TValue newValue) 
{ 
    TValue oldValue; 
    if (dictionary.TryGetValue(key, out oldValue)) 
     return oldValue; 
    else 
    { 
     dictionary.Add(key, newValue); 
     return newValue; 
    } 
} 

(請注意,您可以創建一個接受第二超載。一個Func<TValue>代替TValue,如果值是昂貴創建或引起副作用,這是有用)

現在,這個問題就變得非常簡單:

var dictionary = new Dictionary<int, Dictionary<int, string>>(); 
dictionary.GetOrAdd(key1, new Dictionary<int, string>())[key2] = value; 

我們獲取外鍵的內部字典,或者創建一個新的空字符(如果它不存在),然後我們將新值賦給返回的字典。請注意,索引器將添加一個項目,如果它不存在或更新該項目,如果它已經。

當然秤這相當好,因爲我們添加尺寸以及:

var dictionary = new Dictionary<int, Dictionary<int, Dictionary<int, string>>>(); 
dictionary.GetOrAdd(key1, new Dictionary<int, Dictionary<int, string>>()) 
    .GetOrAdd(key2, new Dictionary<int, string>())[key3] = value; 

在我們的例子中,我們實際上是罰款一直在增加使用我們的GetOrAdd方法TValue的默認值,所以如果我們添加一個過載支持:

public static TValue GetOrAdd<TKey, TValue>(
    this Dictionary<TKey, TValue> dictionary, 
    TKey key) 
    where TValue : new() 
{ 
    TValue oldValue; 
    if (dictionary.TryGetValue(key, out oldValue)) 
     return oldValue; 
    else 
    { 
     var newValue = new TValue(); 
     dictionary.Add(key, newValue); 
     return newValue; 
    } 
} 

它更簡化了代碼:

dictionary.GetOrAdd(key1).GetOrAdd(key2)[key3] = value; 

如果你真的最終做這個特定的操作很多,你可以創建做這件事的方法:

public static void AddMany<TKey1, TKey2, TKey3, TValue>(
    this Dictionary<TKey1, Dictionary<TKey2, Dictionary<TKey3, TValue>>> dictionary, 
    TKey1 key1, 
    TKey2 key2, 
    TKey3 key3, 
    TValue newValue) 
{ 
    dictionary.GetOrAdd(key1).GetOrAdd(key2)[key3] = newValue; 
} 

允許你寫:

dictionary.AddMany(key1, key2, key3, value); 

當然,您需要爲每個要支持的密鑰創建一個新的AddMany重載,並且它必須是編譯時已知的數字,但在您的示例中似乎確實如此。

+0

令人驚歎的解決方案。非常感謝 – 2014-11-06 21:47:12

+0

在情況出現時,我寫了很多解析器代碼,不允許有超過1個變量組合。我使用這些作爲關鍵。是否有可能創建一些方法(params object [] arg),方法將檢測參數號和類型,並執行GetOrAdd。最後一個參數將是價值。 – 2014-11-06 22:24:46

+0

@YousufHossain否,因爲你無法知道任何字典的類型;要知道字典的類型,你需要知道它有多深。 – Servy 2014-11-07 14:53:50