2010-05-11 65 views
12

我有兩個字典具有相同的結構:如何求和C#中兩個字典的值?

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中提出一個解決方案。

+0

是否保證這兩個字典將具有相同的一組密鑰? – Carlos 2010-05-11 16:52:38

+0

@Carlos在這種情況下,是的。但是,看到字典共享一些密鑰而不是其他密鑰的解決方案會很有趣。 – 2010-05-11 16:56:11

回答

12

下面是不是最有效的解決方案(因爲它簡單地將兩個字典爲可枚舉),但它會工作,這是很清楚的:

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

@Ben:感謝您的糾正,我也意識到了這一點。 – 2010-05-11 16:40:06

+0

編輯您的答案,以顯示如何將結果查詢返回到字典中。 – 2010-05-11 16:47:27

+0

@George:謝謝 – 2010-05-11 16:50:19

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) 
+0

感謝您的回答;如果你想計算對象之間的增量,這個答案也有幫助。 – 2010-05-11 17:48:53

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

嗯,我不知道哪些是更多的每fo rmant,但你的解決方案不可讀?

哪些錯誤與

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

嗯,還有'd2'的鍵不在'd1'中,當然...... – 2010-05-11 17:51:41

+0

@Dan Tao是的,這隻對共享鍵有效。 編輯:好的,我添加了解決方案:P – 2010-05-11 17:54:37

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

至少它是(一種?)整齊。

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))); 
    } 
相關問題