LINQ - groupBy with items in several Group
c#, linq
Solution
Given a `MyEnum` and a `MyClass`
[Flags]
enum MyEnum
{
first = 1,
second = 2,
third = 4,
forth = 8
}
class MyClass
{
public MyEnum MyEnum;
public uint Value;
}
And some values
var mcs = new[] {
new MyClass { MyEnum = MyEnum.first | MyEnum.third, Value = 10 },
new MyClass { MyEnum = MyEnum.second, Value = 20 },
new MyClass { MyEnum = MyEnum.first, Value = 100 },
};
This LINQ expression will return for each value of the enum the sum of the values.
var ret = from p in Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()
select new { MyEnum = p, Sum = mcs.Where(q => q.MyEnum.HasFlag(p)).Sum(q => q.Value) };
Note that it will return a "row" even for `MyEnum.fourth` with value `0`.
The expression starts with the values of the enum (`Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()`) and then for each value it sums the values of the `mcs` that have the same `MyEnum` (`mcs.Where(q => q.MyEnum.HasFlag(p)).Sum(q => q.Value)`)
If you want to exclude the values of the enum that aren't used:
var ret = from p in Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()
let temp = mcs.Where(q => q.MyEnum.HasFlag(p)).Select(q => q.Value).ToArray()
where temp.Length > 0
select new { MyEnum = p, Sum = temp.Sum(q => q) };
The expression starts with the values of the enum (`Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()`) and then for each value it "saves" the values of the `mcs` that have the same `MyEnum` (`let temp = mcs.Where(q => q.MyEnum.HasFlag(p)).Select(q => q.Value).ToArray()`) in `temp`, skips the `temp` that are empty (`where temp.Length > 0`) and sum the remaining `temp` (`select new { MyEnum = p, Sum = temp.Sum(q => q) }`). Note that if you use an `uint` you have to use `temp.Sum(q => q)`, but with an `int` you can use `temp.Sum()` (or you can use `temp.Sum(q => q)`).
Another way is through a double `from` and a `group by`
var ret = from p in Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()
from q in mcs
where q.MyEnum.HasFlag(p)
group q.Value by p into r
select new { MyEnum = r.Key, Sum = r.Sum(p => p) };
It's probably equivalent to using the `SelectMany` as suggested by ChaseMedallion (a double `from` is converted by the compiler to a `SelectMany`)
Problem
I have a list of object that has two properties, let's say `a` and `b`. `a` is an Enum like: ``` [Flags] enum MyEnum { first = 1, second = 2, third = 4, fourth = 8 }; ``` `b` is an unsigned integer, which is a mask (combination of the MyEnum flags). now i need to sum every object by their `a` - meaning an object can be summed twice if `obj.a = first | third` and i can't seem to do a `groupBy` to them. is there a different way to sum them? I'm sorry i don't share my code, but i can't. i can tell you i did it using foreach in just some if - else blocks but i think i should learn how to do it in Linq EDIT: I think i wasn't clear. i want to sum the object by the Enum, meaning if i have: ``` obj1.a = first, obj1.b = 5 obj2.a = first | second, obj2.b = 3 ``` then the output will be ``` first sum = 8 second sum = 3 ```