.net 如何合并两个字典,而不会在键上出现ArgumentException?

bn31dyow  于 2022-11-26  发布在  .NET
关注(0)|答案(4)|浏览(214)

当我试图合并两个字典时,我不知道如何保留字典上的键和值。由于键重复,我一直得到ArgumentException。当键匹配时,我只想通过=+ kvp.value;添加值
我有一个字典列表
第一个字典= kvp = "jump", 2;
第二字典= kvp = "jump", 4;
我喜欢把它们合并,得到类似这样的结果:字典= kvp = "jump", 6;
我可以在以后添加到我的词典列表中
我试图运行我在StackOverflow线程中发现的东西。

foreach (var dict in listOfDict)
{
         dict.SelectMany(d => d)
            .ToLookup(pair => pair.Key, pair => pair.Value)
            .ToDictionary(group => group.Key, group => group.First());
}

但我一直在想。
无法从用法推断出。请尝试显式指定类型参数。
我希望避免在单独的列表中获取所有键和所有值,以便在以后循环访问时在新字典中添加键和值。

zpgglvta

zpgglvta1#

使用Linq对双精度值字典列表的最简单扩展:

public static class ExtListOfDict {
    public static Dictionary<TKey, double> SumValue1<TKey>(this List<Dictionary<TKey, double>> list)        
        => list?.SelectMany(i => i).ToLookup(i => i.Key, i => i.Value).ToDictionary(i => i.Key, i => i.Sum());

}

无链接:

public static Dictionary<TKey, double> SumValue2<TKey>(this List<Dictionary<TKey, double>> list) {
    if(list?.Count > 0) {
        var dir = new Dictionary<TKey, double>(list[0]);
        for(var i = 1; i < list.Count; i++) 
            foreach (var kv in list[i])
                if (dir.TryGetValue(kv.Key, out double sum))
                    dir[kv.Key] = sum + kv.Value; 
                else 
                    dir.Add(kv.Key, kv.Value);                    
        return dir;
    } else
        return null;
}
kxxlusnw

kxxlusnw2#

如果您喜欢LINQ方法,我会选择类似以下的方法:

var dictionaries = new List<Dictionary<string, int>>(); // this is the list of dictionaries you want to merge
    var unifiedDictionary = new Dictionary<string, int>(); // this is the dictionary where you merge and add the values

    foreach (var kvp in dictionaries.SelectMany(dictionary => dictionary))
    {
        if (unifiedDictionary.ContainsKey(kvp.Key))
        {
            unifiedDictionary[kvp.Key] += kvp.Value;
        }
        else
        {
            unifiedDictionary.Add(kvp.Key, kvp.Value);
        }
    }

但是,如果这太难阅读(我并不总是喜欢在显式代码块上使用过多的LINQ),您可以使用for-loop方法:

var dictionaries = new List<Dictionary<string, int>>(); // this is the list of dictionaries you want to merge
    var unifiedDictionary = new Dictionary<string, int>(); // this is the dictionary where you merge and add the values

    foreach (var dictionary in dictionaries)
    {
        foreach (var kvp in dictionary)
        {
            if (unifiedDictionary.ContainsKey(kvp.Key))
            {
                unifiedDictionary[kvp.Key] += kvp.Value;
            }
            else
            {
                unifiedDictionary.Add(kvp.Key, kvp.Value);
            }
        }
    }

希望这对你有帮助。如果需要进一步的帮助和解释,请告诉我。

ncecgwcz

ncecgwcz3#

下面是一个基于CollectionsMarshal.GetValueRefOrAddDefault API(.NET 6)和INumber<TSelf>接口(.NET 7)的解决方案:

public static Dictionary<TKey, TValue> ToSumDictionary<TKey, TValue>(
    this IEnumerable<Dictionary<TKey, TValue>> dictionaries)
    where TValue : struct, INumber<TValue>
{
    ArgumentNullException.ThrowIfNull(dictionaries);
    Dictionary<TKey, TValue> result = null;
    foreach (var dictionary in dictionaries)
    {
        if (result is null)
        {
            result = new(dictionary, dictionary.Comparer);
            continue;
        }
        if (!ReferenceEquals(dictionary.Comparer, result.Comparer))
            throw new InvalidOperationException("Incompatible comparers.");
        foreach (var (key, value) in dictionary)
        {
            ref TValue refValue = ref CollectionsMarshal
                .GetValueRefOrAddDefault(result, key, out bool exists);
            refValue = exists ? refValue + value : value;
        }
    }
    result ??= new();
    return result;
}

每个字典中每个KeyValuePair<TKey, TValue>的键只散列一次。

vptzau2j

vptzau2j4#

如果您因为重复的键而得到异常,那么听起来就像您有重复的键!
在尝试合并两个字典之前,您是否检查过它们?简单地调用=+ kvp.value,而不检查第一个字典是否已经有该名称的键,这很可能是您的问题。
您需要检查具有该键的现有条目,如果找到,则采取适合您的场景的任何操作(即忽略、覆盖、要求用户决定等)

相关问题