代码之家  ›  专栏  ›  技术社区  ›  George Stocker NotMe

如何用C对两个字典中的值求和?

  •  13
  • George Stocker NotMe  · 技术社区  · 15 年前

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

    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 回复  |  直到 6 年前
        1
  •  13
  •   George Stocker NotMe    15 年前

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

    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);
    
        2
  •  4
  •   Carlos    15 年前

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

    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
  •  4
  •   Stephan    15 年前
    (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)
    
        4
  •  3
  •   Francisco Noriega    15 年前

    嗯,我不知道哪一个更符合形式,但是你的解决方案怎么不可读呢?

    怎么了?

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

    编辑2:

    为了获得所有键/值,如果它们不相同,则如下所示:

       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]);
           }
    
        5
  •  2
  •   Dan Tao    15 年前

    像这样的东西怎么样?

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

    至少是(有点?)整洁的

        6
  •  1
  •   Charles    12 年前

    我编写了一个扩展方法,将字典列表与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 ) ) );
        }