[英]LINQ - groupBy with items in several Group
I have a list of object that has two properties, let's say a
and b
. 我有一个对象列表,它有两个属性,比方说a
和b
。 a
is an Enum like: a
是一个Enum,如:
[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). b
是无符号整数,它是一个掩码 (MyEnum标志的组合)。
now i need to sum every object by their a
- meaning an object can be summed twice if obj.a = first | third
现在我需要通过自己的总结每个对象a
-这意味着一个对象可以被归纳如果两次obj.a = first | third
obj.a = first | third
and i can't seem to do a groupBy
to them. obj.a = first | third
,我似乎groupBy
与他们做一个groupBy
。 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 我可以告诉你,我只是在一些if - else块中使用foreach,但我想我应该学习如何在Linq中做到这一点
EDIT: I think i wasn't clear. 编辑:我想我不清楚。 i want to sum the object by the Enum, meaning if i have: 我想通过Enum总结对象,这意味着如果我有:
obj1.a = first, obj1.b = 5
obj2.a = first | second, obj2.b = 3
then the output will be 然后输出将是
first sum = 8
second sum = 3
Try using HasFlag and GetValues to extract all the flags for a particular enum value: 尝试使用HasFlag和GetValues提取特定枚举值的所有标志:
var objs = new[] { new { a = MyEnum.first | MyEnum.second }, new { a = MyEnum.first }... };
var enumValues = Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().ToArray();
// first, use SelectMany to create a sequence with one instance of each object for
// each flag value in it's a
var grouped = objs.SelectMany(
o => enumValues.Where(flag => o.a.HasFlag(flag))
.Select(v => new { o, flag })
)
// then group by the extracted flag value
// the element selector (t => t.o) gets us back to an IGrouping of o's (dropping the extra flag property
.GroupBy(t => t.flag, t => t.o);
// finally, we can get sums by a as follows:
var sumsByA = grouped.ToDictionary(g => g.Key, g => g.Sum(o => o.b));
Given a MyEnum
and a MyClass
给出一个MyEnum
和一个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. 此LINQ表达式将为枚举的每个值返回值的总和。
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
. 请注意,即使对于值为0
MyEnum.fourth
,它也将返回“行”。
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)
) 表达式以枚举值( Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()
) Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()
,然后对于每个值,它将具有相同MyEnum
的mcs
的值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) }
). 表达式以枚举值( Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()
) Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()
,然后对于每个值,它“保存”具有相同MyEnum
的mcs
的值( let temp = mcs.Where(q => q.MyEnum.HasFlag(p)).Select(q => q.Value).ToArray()
在temp
let temp = mcs.Where(q => q.MyEnum.HasFlag(p)).Select(q => q.Value).ToArray()
),跳过空的temp
( where temp.Length > 0
)和sum剩余的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)
). 请注意,如果使用uint
,则必须使用temp.Sum(q => q)
,但使用int
可以使用temp.Sum()
(或者可以使用temp.Sum(q => q)
)。
Another way is through a double from
and a group by
另一种方式是通过一个双from
和一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
) 这可能相当于使用SelectMany
通过ChaseMedallion(双所建议from
由编译器变换为一个SelectMany
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.