Как суммировать значения из двух словарей в C #? - PullRequest
13 голосов
/ 11 мая 2010

У меня есть два словаря с одинаковой структурой:

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 ]

14 голосов
/ 11 мая 2010

Следующее не является самым эффективным решением (потому что оно просто обрабатывает оба словаря как перечислимые), но оно будет работать, и это совершенно ясно:

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);
4 голосов
/ 11 мая 2010

Если у вас есть чугунная гарантия, что два набора ключей одинаковы:

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));
4 голосов
/ 11 мая 2010
(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)
3 голосов
/ 11 мая 2010

Ммм, я не знаю, что больше на формант, но как ваше решение не читается?

Что не так с

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

Я на самом деле думаю, что это более понятно, чем некоторые решения linq. Несмотря на то, что я не проверял его, я думаю, что он мог бы иметь более высокую производительность, поскольку он перечисляет только ключи в одном словаре, а не значения, но вы бы использовали фактическое хеширование (или то, что является базовой реализацией словаря) найдите значения, что является самым быстрым способом их получения.

EDIT:

для решения, где ключи не всегда будут одинаковыми, если вы хотите получить общие, вам нужно только добавить строку;

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]);
       }
2 голосов
/ 07 февраля 2013

Я написал небольшой метод расширения, который объединит список словарей со значениями 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 ) ) );
    }
2 голосов
/ 11 мая 2010

Как насчет этого?

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

По крайней мере, это (вроде?) Аккуратно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...