2010-05-11 9 views
12

I는 동일한 구조를 가진 두 개의 사전을 가지고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 } 
}; 

I는 키 제 사전 함께 사전의 값을 합산하고 돌아가, 그리고 할 각 키의 총 값 :

Table, 9 
Chair, 10 
Couch, 9 

현재 해결 방법은 사전을 반복하여 빼내는 것입니다. 그러나 그 해결책은 가장 실적이 좋지 않거나 가장 판독 가능하지 않습니다. 그러나 저는 LINQ에서 해결책을 제시하려고 벽돌 벽을 치고 있습니다. (단순히 enumerables로 모두 사전을 취급하기 때문에)

+0

두 개의 사전에 동일한 키가 있어야합니까? – Carlos

+0

이 경우 @Carlos, 예. 그러나 사전이 일부 키를 공유하고 다른 키는 공유하지 않는 솔루션을 보는 것은 흥미로울 것입니다. –

답변

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 : 수정 해 주셔서 감사합니다. –

+0

대답을 편집하여 결과 쿼리를 사전에 다시 가져 오는 방법을 보여줍니다. –

+0

@ 조지 : 감사합니다 –

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

답변 해 주셔서 감사합니다. 이 대답은 객체 사이의 델타를 계산하려는 경우에도 도움이됩니다. –

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

음, 어느 것이 더 많은지 몰라요. 하지만 솔루션은 어떻게 읽을 수 없습니까?

무슨 잘못

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

와?

저는 실제로 linq 솔루션 중 일부보다 더 명확하다고 생각합니다. 비록 테스트하지는 않았지만, 성능이 좋을 수 있다고 생각합니다. 값이 아닌 하나의 사전에있는 키만 열거하기 때문에 실제 해싱 (또는 사전의 기본 구현이 무엇이든)을 사용할 수 있습니다. 그 (것)들을 얻는 가장 빠른 방법 인 가치를 찾아 내십시오.

편집 : 만 공유 사람을 얻으려면 키 항상, 당신은 단지 라인을 추가 할 필요가, 동일 wouldnt가 솔루션에 대한

;

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'에없는 열쇠를 가지고 있습니다 ... –

+0

@Dan Tao 예, 공유 키에서만 작동합니다. 편집 : 알았어 그 해결책을 추가 : P는 –

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))); 
    } 
관련 문제