C#将键和值添加到嵌套字典的简单方法?

时间:2014-11-06 20:45:09

标签: c# dictionary

是否有一种简单的方法可以为嵌套字典添加值。我正在寻找一种方法来轻松替换以下类型的代码。

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

2 个答案:

答案 0 :(得分:5)

我们可以编写一个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;

在我们的情况下,我们实际上总是使用TValue方法添加默认值GetOrAdd,所以如果我们添加一个重载来支持:

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;

如果你真的最终完成了这个特定的操作 lot ,你可以创建一个方法来完成整个事情:

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重载,并且它必须是编译时已知的数字,但在您的情况下确实如此。示例

答案 1 :(得分: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>