Thorion
Thorion

Reputation: 27

Sum multiple lists of ints into one by grouping using LINQ

I have List of items.

Item is specified like:

public class Item
{
    public List<decimal> Values { get; set; }

    public string GroupingKey { get; set; }

    public List<int> Cycle { get; set; }
}

I want to group a List of Item instances by grouping key and sum Values by index in list and add into one list. Cycle list is same for each group so just add this into new group

For example, the following List:

List<Items>
{
    Values { 2, 3, 5 },
    GroupingKey = "P23",
    Cycle { 1, 2, 3, 4 }
},
{
    Values { 10, 20, 30 },
    GroupingKey = "P23",
    Cycle { 1, 2, 3, 4 }
},
{
    Values { 10, 20, 30 },
    GroupingKey = "P24",
    Cycle { 1, 2, 3, 4 }
}

would end up looking like:

List<Items>
{
    Values { 12, 23, 35},
    GroupingKey = "P23",
    Cycle { 1, 2, 3, 4}
},
{
    Values { 10, 20, 30},
    GroupingKey = "P24",
    Cycle { 1, 2, 3, 4}
}

Item instances with same key can be more and not only two. Any ideas on how to solve this using LINQ?

Thank you.

Upvotes: 1

Views: 1109

Answers (2)

matramos
matramos

Reputation: 86

You can achieve that by using a bunch of GroupBy and Select's:

var result = list.GroupBy(i => i.GroupingKey).ToList().Select(group => new Item
{
    Values = group.SelectMany(item => item.Values
                .Select((value, index) => new {value, index}))
                      .GroupBy(item => item.index)
                      .Select(a => a.Sum(e => e.value)).ToList(),
    GroupingKey = group.Select(i => i.GroupingKey).FirstOrDefault(),
    Cycle = group.Select(i => i.Cycle).FirstOrDefault()
});

Upvotes: 2

Douglas
Douglas

Reputation: 54887

What you need is an Enumerable.Zip method that works across multiple sequences. Unfortunately, LINQ doesn't provide such, so we have to project the indexes and sum the elements manually.

    var merged = items
        .GroupBy(x => x.GroupingKey)
        .Select(grp => new Item
        {
            Values = Enumerable
                .Range(0, grp.Max(x => x.Values.Count))
                .Select(i => grp.Sum(x => x.Values.Count > i ? x.Values[i] : 0))
                .ToList(),
            GroupingKey = grp.Key,
            Cycle = grp.First().Cycle   // can add check that others are identical
        })
        .ToList();

Upvotes: -1

Related Questions