2014-11-06 46 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