如何在C#中对两个词典中的值求和?

时间:2010-05-11 16:35:34

标签: c# .net linq dictionary sum

我有两个结构相同的词典:

Dictionary<string, int> foo = new Dictionary<string, int>() 
{
    {"Table", 5 },
    {"Chair", 3 },
    {"Couch", 1 }
};

Dictionary<string, int> bar = new Dictionary<string, int>() 
{
    {"Table", 4 },
    {"Chair", 7 },
    {"Couch", 8 }
};

我想将字典的值加在一起,并返回第三个带字符串的词典,以及每个键的总值:

Table, 9
Chair, 10
Couch, 9

我目前的解决方案是遍历字典并以这种方式将其拉出来,但我知道解决方案不是性能最高或最易读的。但是,我正试图在LINQ中找到解决方案。

6 个答案:

答案 0 :(得分:14)

以下不是最有效的解决方案(因为它只是将两个词典都视为枚举),但它会起作用并且非常清楚:

Dictionary<string, int> result = (from e in foo.Concat(bar)
              group e by e.Key into g
              select new { Name = g.Key, Count = g.Sum(kvp => kvp.Value) })
              .ToDictionary(item => item.Name, item => item.Count);

答案 1 :(得分:4)

(from a in foo
join b in bar on a.Key equals b.Key
select new { Key = a.Key, Value = a.Value + b.Value })
.ToDictionary(a => a.Key,a => a.Value) 

应该这样做。

编辑:可能更有效率(不确定如何实现连接)

(from a in foo
let b = bar.ContainsKey(a.Key) ? (int?)bar[a.Key] : null
select new { Key = a.Key, Value = a.Value + (b != null ? b : 0) }
).ToDictionary(a => a.Key, a => a.Value)

答案 2 :(得分:4)

如果您有铸铁保证两组钥匙相同:

Dictionary<string, int> Res2 = foo.ToDictionary(orig => orig.Key, orig => orig.Value + bar[orig.Key]);

如果按键设置不同,我可以提出最佳效果:

var AllKeys = foo.Keys.Union(bar.Keys);
var res3 = AllKeys.ToDictionary(key => key,  key => (foo.Keys.Contains(key)?foo[key] : 0) + (bar.Keys.Contains(key)?bar[key] : 0));

答案 3 :(得分:3)

嗯,我不知道哪个更适合每个人,但你的解决方案怎么不可读?

出了什么问题
  foreach (string key in d1.Keys)
  {
     d3.Add(key,d1[key]+d2[key]);
  }

我实际上认为它比一些linq解决方案更清晰。即使我没有测试它,我认为它可以有更好的性能,因为它只枚举一个字典中的键而不是值,你使用实际的散列(或者字典的底层实现)找到值,这是获得它们的最快方法。

编辑:

对于密钥不一定相同的解决方案,如果您只想获得共享密钥,则只需添加一行;

foreach (string key in d1.Keys)
  {
     if(d2.ContainsKey(key)
        d3.Add(key,d1[key]+d2[key]);
  }

EDIT2:

为了获得所有键/值,如果它们不相同,那么它就像这样:

   foreach (string key in d1.Keys)
      {
         if(d2.ContainsKey(key)
            d3.Add(key,d1[key]+d2[key]);
         else
            d3.Add(key,d1[key])
      }

   foreach (string key in d2.keys)
       {
          if(!d1.ContainsKey(key) // only get keys that are unique to d2
             d3.Add(key,d2[key]);
       }

答案 4 :(得分:2)

这样的事情怎么样?

var fooBar = foo.Keys
    .Union(bar.Keys)
    .Select(
        key => {
            int fval = 0, bval = 0;

            foo.TryGetValue(key, out fval);
            bar.TryGetValue(key, out bval);

            return new KeyValuePair<string, int>(key, fval + bval);
        }
    )
    .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

至少它(有点?)整洁。

答案 5 :(得分:1)

我写了一个小的扩展方法,它将一个字典列表与Int值合并。我使用了这个问题的代码来实现它,所以我正在分享

    public static Dictionary<TSource, Int32> MergeIntDictionary<TSource>( this ICollection<Dictionary<TSource, Int32>> source )
    {
        return source.Aggregate( ( cur, next ) => cur.Concat( next )
            .GroupBy( o => o.Key )
            .ToDictionary( item => item.Key, item => item.Sum( o => o.Value ) ) );
    }