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

本文关键字:简单 方法 键和值 添加 嵌套 字典 | 更新日期: 2023-09-27 18:29:23

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

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

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

我们可以编写一个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重载,并且它必须是编译时已知的数字,但在您的示例中似乎确实是这样。

您可以简化内部:

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>