Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merging duplicate elements within an IEnumerable

Tags:

c#

.net

linq

I currently have an IEnumerable<MyObject> where MyObject has the properties String Name and long Value.

If i was to have within the Enumerable, 10 instances of MyObject, each with a different name and value, with the exception of one having the same name as the other.

Does .NET (or LINQ) have a built in method which will allow me to find the duplicate, and if possible, merge the Value property so that there ends up being only 9 elements within the enumerable, each with a distinct Name and the one that had a duplicate has the Value that is equal to the sum of its self and the duplicate.

So far i have found that the only way to iterate over the entire IEnumerable and look for the duplicates and generate a new IEnumerable of unique items, but this seems untidy and slow.

like image 634
bizzehdee Avatar asked Sep 09 '13 10:09

bizzehdee


3 Answers

list.GroupBy(e => e.Name).Select(group => new MyObject
    {
        Name = group.Key,
        Value = group.Sum(e => e.Value)
    }
)

Update:
Another variant:

list.GroupBy(
    e => e.Name,
    e => e,
    (name, group) => group.Aggregate((result, e) =>
        {
            result.Value += e.Value;
            return result;
        }
    )
)
like image 114
Vladimir Avatar answered Nov 08 '22 17:11

Vladimir


You can group items by name and project results to 'merged' objects:

objects.GroupBy(o => o.Name)
       .Select(g => new MyObject { Name = g.Key, Value = g.Sum(o => o.Value) });

UPDATE: Another option, if new MyObject instantiation is undesired (e.g. you have many properties in this class, or you should preserver references) then you can use aggregation with first item in group as accumulator:

objects.GroupBy(o => o.Name)
       .Select(g => g.Skip(1).Aggregate(
                        g.First(), (a, o) => { a.Value += o.Value; return a; }));
like image 44
Sergey Berezovskiy Avatar answered Nov 08 '22 18:11

Sergey Berezovskiy


I dont know a single method solution but what about:

set.GroupBy(g=>g.Name).Select(g=> new MyObject{Name=g.Key, Value=g.Sum(i=>i.Value)});
like image 3
Not loved Avatar answered Nov 08 '22 17:11

Not loved