Линк пересекаются с суммой - PullRequest
2 голосов
/ 21 октября 2011

У меня есть две коллекции, которые я хочу пересечь и выполнить операцию суммирования для соответствующих элементов.

Например, коллекции (в псевдокоде):

col1 = { {"A", 5}, {"B", 3}, {"C", 2} }
col2 = { {"B", 1}, {"C", 8}, {"D", 6} }

ижелаемый результат:

intersection = { {"B", 4}, {"C", 10} }

Я знаю, как использовать IEqualityComparer для сопоставления элементов их имени, но как суммировать значения при пересечении?

РЕДАКТИРОВАТЬ:

В начальных коллекциях нет двух предметов с одинаковым именем.

Ответы [ 4 ]

1 голос
/ 21 октября 2011

Лучшее, что я придумал до сих пор (мои коллекции на самом деле Dictionary<string, int> экземпляры):

var intersectingKeys = col1.Keys.Intersect(col2.Keys);
var intersection = intersectingKeys
    .ToDictionary(key => key, key => col1[key] + col2[key]);

Я не уверен, что это будет работать хорошо, по крайней мере, читабельно.

1 голос
/ 21 октября 2011

Допустим, ваши входные данные выглядят так:

IEnumerable<Tuple<string, int>> firstSequence = ..., secondSequence = ...;

Если строки уникальны в каждой последовательности (т. Е. В каждой последовательности может быть не более одного {"A", XXX})Вы можете join вот так:

var query = from tuple1 in firstSequence
            join tuple2 in secondSequence on tuple1.Item1 equals tuple2.Item1
            select Tuple.Create(tuple1.Item1, tuple1.Item2 + tuple2.Item2);

Вы также можете рассмотреть возможность использования group by, что было бы более уместно, если бы эта уникальность не выполнялась:

var query = from tuple in firstSequence.Concat(secondSequence)
            group tuple.Item2 by tuple.Item1 into g
            select Tuple.Create(g.Key, g.Sum());

Если ни то, ни другое вам не нужно, уточните ваши требования более точно.

РЕДАКТИРОВАТЬ : После того, как вы пояснили, что это словари, ваше существующее решение в порядке.Вот еще один вариант с join:

var joined = from kvp1 in dict1
             join kvp2 in dict2 on kvp1.Key equals kvp2.Key
             select new { kvp1.Key, Value = kvp1.Value + kvp2.Value };

var result = joined.ToDictionary(t => t.Key, t => t.Value);

или в свободном синтаксисе:

var result = dict1.Join(dict2,
                        kvp => kvp.Key,
                        kvp => kvp.Key,
                        (kvp1, kvp2) => new { kvp1.Key, Value = kvp1.Value + kvp2.Value })
                  .ToDictionary(a => a.Key, a => a.Value);
1 голос
/ 21 октября 2011

Это даст результат, но есть некоторые предостережения. Он объединяет две коллекции, а затем группирует их по буквам. Таким образом, если, например, col1 содержит два A элемента, он суммирует их вместе, и, поскольку теперь они равны 2 A, он возвращает их.

var col1 = new[] { new { L = "A", N = 5 }, new { L = "B", N = 3 }, new { L = "C", N = 2 } };
var col2 = new[] { new { L = "B", N = 1 }, new { L = "C", N = 8 }, new { L = "D", N = 6 } };

var res = col1.Concat(col2)
              .GroupBy(p => p.L)
              .Where(p => p.Count() > 1)
              .Select(p => new { L = p.Key, N = p.Sum(q => q.N) })
              .ToArray();
0 голосов
/ 21 октября 2011

Если ваш алгоритм пересечения приведет к анонимному типу, то есть ...Select(new { Key = key, Value = value}), тогда вы можете легко суммировать его

result.Sum(e => e.Value);

Если вы хотите суммировать "while", выполняющее пересечение, добавьте значениезначение аккумулятора при добавлении в набор результатов.

...