如何合并多个LINQ生成的字典并按需聚合对应值?
合并多个LINQ生成的字典并聚合对应值的解决方案
嘿,我来帮你搞定这个字典合并和聚合的问题!首先得先解决一个关键的小坑:你现在用的匿名类型作为字典键,虽然三个字典的键结构看起来一样,但编译器会为每个GroupBy里的匿名类型生成不同的隐式类型——这意味着即使两个键的属性值完全相同,它们也会被当成不同的键处理,直接合并会出问题。所以第一步要先统一键的类型,再进行合并聚合。
下面给你两种实用的方案:
方案一:提前统一键类型(推荐)
先定义一个值类型的键结构,比如用C# 9+的record(它默认按属性值比较,完美适合做字典键):
// 根据你的实际属性类型调整,比如Property1可能是string、Guid等 public record DataKey(int Property1, int Property2, int LocalCcyId);
然后修改你原来的字典创建代码,把匿名类型替换成这个DataKey:
var dictionaryOne = _repositoryOne.GetData() .GroupBy(d => new DataKey(d.Property1, d.Property2, d.LocalCcyId)) .ToDictionary(g => g.Key, v => v.Sum(l => ConvertToUsd(effectiveDate, l.LocalCcyId, l.Amount))); var dictionaryTwo = _repositoryTwo.GetData() .GroupBy(d => new DataKey(d.Property1, d.Property2, d.LocalCcyId)) .ToDictionary(g => g.Key, v => v.Sum(l => ConvertToUsd(effectiveDate, l.LocalCcyId, l.Amount))); // dictionaryThree同理修改
现在三个字典的键类型完全一致,直接用LINQ合并并聚合:
var mergedDictionary = dictionaryOne .Concat(dictionaryTwo) .Concat(dictionaryThree) .GroupBy(kv => kv.Key) .ToDictionary(g => g.Key, g => g.Sum(kv => kv.Value));
这个方案的好处是类型安全,代码可读性高,后续维护也方便。
方案二:不修改原有字典,用元组做中间键
如果不想改动已有的字典创建代码,可以把每个字典的匿名键映射成值元组(元组也是按值比较的,结构相同、值相同就会被视为相等):
var mergedDictionary = dictionaryOne // 把匿名键转成元组 .Select(kv => (Key: (kv.Key.Property1, kv.Key.Property2, kv.Key.LocalCcyId), Value: kv.Value)) // 合并第二个字典的键值对 .Concat(dictionaryTwo.Select(kv => (Key: (kv.Key.Property1, kv.Key.Property2, kv.Key.LocalCcyId), Value: kv.Value))) // 合并第三个字典的键值对 .Concat(dictionaryThree.Select(kv => (Key: (kv.Key.Property1, kv.Key.Property2, kv.Key.LocalCcyId), Value: kv.Value))) // 按元组键分组,求和对应的值 .GroupBy(item => item.Key) .ToDictionary(g => g.Key, g => g.Sum(item => item.Value));
这个方案适合快速临时处理,不需要额外定义类,但元组的可读性不如命名的record。
补充说明
- 不管用哪种方案,最终的效果都是:相同键的值会被累加,唯一键的值保持不变,完全满足你“按需聚合对应值”的需求。
- 如果你的C#版本低于9.0,没法用
record,可以换成struct并手动重写Equals和GetHashCode方法,或者用旧的System.Tuple,不过值元组和record是更简洁的选择。
内容的提问来源于stack exchange,提问作者Rahul Misra
相关产品推荐
相关产品推荐

