5

我有一个具有两个属性的对象列表,比如说aba是一个枚举,如:

[Flags] enum MyEnum
{
    first  = 1,
    second = 2,
    third  = 4,
    fourth = 8
};

b是一个无符号整数,它是一个掩码(MyEnum 标志的组合)。

现在我需要通过它们对每个对象求和- 这意味着如果我似乎无法对它们做一个a对象,则可以将一个对象求和两次。有没有不同的方法来总结它们?obj.a = first | thirdgroupBy

对不起,我不分享我的代码,但我不能。我可以告诉你我只是在一些 if - else 块中使用 foreach 做到了,但我认为我应该学习如何在 Linq 中做到这一点

编辑: 我想我不清楚。我想通过枚举对对象求和,这意味着如果我有:

obj1.a = first, obj1.b = 5
obj2.a = first | second, obj2.b = 3

那么输出将是

first sum = 8
second sum = 3
4

2 回答 2

3

给定一个MyEnum和一个MyClass

[Flags]
enum MyEnum
{
    first = 1,
    second = 2,
    third = 4,
    forth = 8
}

class MyClass
{
    public MyEnum MyEnum;
    public uint Value;
}

还有一些价值观

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 },
};

此 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) };

请注意,即使对于MyEnum.fourthvalue ,它也会返回一个“行” 0

该表达式以枚举 ( Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()) 的值开始,然后对于每个值,它将mcs具有相同MyEnum( mcs.Where(q => q.MyEnum.HasFlag(p)).Sum(q => q.Value))的值相加

如果要排除未使用的枚举值:

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) };

该表达式以枚举 ( Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()) 的值开始,然后对于每个值,它“保存”mcs中具有相同MyEnum( let temp = mcs.Where(q => q.MyEnum.HasFlag(p)).Select(q => q.Value).ToArray()) 的值temp,跳过temp空的 ( where temp.Length > 0) 并对剩余的temp( select new { MyEnum = p, Sum = temp.Sum(q => q) }) 求和。请注意,如果您使用 an uint,则必须使用temp.Sum(q => q),但使用 anint您可以使用temp.Sum()(或者您可以使用temp.Sum(q => q))。

另一种方法是通过一个 doublefrom和一个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) };

它可能相当于使用SelectManyChaseMedallion 建议的使用(from编译器将 double 转换为 a SelectMany

于 2013-08-02T09:50:10.363 回答
3

尝试使用 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));
于 2013-08-02T09:43:08.367 回答