2013-08-02 80 views
6

我有一個對象的列表有兩個屬性,比如說aba是一個枚舉像:LINQ - groupBy與幾個組中的項

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

b是無符號整數,它是一個掩模(所述MyEnum標誌的組合)。

現在我需要通過總結每個對象的a - 這意味着一個對象可以歸納如果兩次obj.a = first | third,我似乎無法做一個groupBy他們。有沒有不同的方法來總結它們?

對不起,我不分享我的代碼,但我不能。我可以告訴你,我沒有使用它的foreach的只是一些,如果 - else塊,但我想我應該學會如何做到這一點Linq中

編輯: 我想我並不清楚。我要總結由枚舉的對象,這意味着如果我有:

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

那麼輸出將是

first sum = 8 
second sum = 3 
+0

可能你的建議提供預期的結果?你的問題不是很清楚我的問題 –

+0

你的問題仍然不清楚。如果我們有'obj3 = first |怎麼辦?秒|第三;「什麼是和?他們可以是「第一總和= 15」,「第二總和= 8」,「第三總和= 3」,「第四總和= 7」,「第五總和= 8」,「第六總和= 14」 –

+0

@KingKing正好。我通過枚舉值求和,所以如果一個對象在枚舉中的第一個|第二個|第三個和第三個值的字段中,那麼3將被添加到第一個,第二個和第三個之和 –

回答

3

給定一個MyEnumMyClass

[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.fourth與價值0

表達始於枚舉(Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>())的值,然後對每個值它總結認爲有mcs的值相同MyEnummcs.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(在temp中跳過tempwhere temp.Length > 0),並將其餘的tempselect new { MyEnum = p, Sum = temp.Sum(q => q) })加起來。請注意,如果您使用uint,則必須使用temp.Sum(q => q),但要使用int,則可以使用temp.Sum()(或者您可以使用temp.Sum(q => q))。

另一種方式是通過雙fromgroup 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) }; 

這可能等同於使用SelectMany通過ChaseMedallion(雙from被編譯器轉換爲SelectMany

+0

哇,真的很感謝你。非常好解釋,也適合未來使用。優秀的答案 –

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)); 
+0

謝謝你的回答,真的很好,解釋一下,會盡量試試就是ASAP –