Linq 跨两个字典聚合数据

本文关键字:字典 数据 两个 Linq | 更新日期: 2023-09-27 18:37:17

我正在努力完成以下任务:

Dict1
1     0
2     0
3     1
4     1
5     2
6     2
7     2
Dict2
1     45
2     30
3     31
4     43
5     20
6     10
7     5

我想根据字典 2 中的匹配键对字典 1 中的值求和,并返回 max 或任何默认键,结果汇总不包括字典 1 中带有 0 的值。

例如:

New Dict
1    45
2    30
4    74
7    35

Linq 跨两个字典聚合数据

因此,您希望从第一个词典中获取值不为零的所有对,按字典值对它们进行分组,然后对于每个组,它将表示新字典中的一个条目。 该条目的键是组中的最大键,值是该键的第二个字典中的值的总和。

然后只需将零值添加到末尾Concat并将其放入字典中:

var newDict = dict1.Where(pair => pair.Value != 0)
        .GroupBy(pair => pair.Value)
        .Select(group => new KeyValuePair<int, int>(
            group.Max(pair => pair.Key),
            group.Where(pair => dict2.ContainsKey(pair.Key))
                .Sum(pair => dict2[pair.Key])))
        .Concat(dict1.Where(pair => pair.Value == 0))
        .ToDictionary(pair => pair.Key, pair => pair.Value);

听起来您实际上是按字典 1 中的值进行分组。我怀疑你想要这样的东西

var sums = from p1 in dict1
             where p1.Value != 0
             join p2 in dict2 on p1.Key equals p2.Key
             group p2 by p1.Value into g
             select new { Key = g.Max(p2 => p2.Key),
                          Sum = g.Sum(p2 => p2.Value) };

这给出了以下结果:

4 74
7 35

它不包括您的 {1, 45} 或 {2, 30} 结果。我以为你想忽略第一个字典中值为 0 的条目?

我想

添加这个答案作为参考。我不明白为什么其他答案从dict1开始?虽然当我们从这样的dict2开始时,它会更加方便和容易:

var result = dict2.GroupBy(x => dict1[x.Key] == 0 ? dict1.Min(a=>a.Value) - x.Key :
                                                              dict1[x.Key])
                  .ToDictionary(g => g.Max(x=>x.Key), g => g.Sum(x => x.Value));

或者如果你不关心1-line LINQ solution,只需声明一些保存 dict1 最小值的变量(这种方式当然有更好的性能):

var min = dict1.Min(a=>a.Value);
var result = dict2.GroupBy(x => {
                     var d = dict1[x.Key];
                     return d == 0 ? min - Math.Abs(x.Key) : d;
                  }).ToDictionary(g => g.Max(x=>x.Key), g => g.Sum(x => x.Value));

注意:上面的代码可以在某些有限的条件下工作,它不会检查key existence,因为它假设 2 个字典具有相同的密钥集合(或者至少 dict2 中的所有密钥都可以在 dict1 中找到。如果dict2中有一个条目与dict1中的任何键不匹配,我们需要更多的规则来处理这种情况,例如将原始条目保留在dict2...