2013-08-02 9 views
6

मेरे पास ऑब्जेक्ट की एक सूची है जिसमें दो गुण हैं, मान लें a और ba एक Enum की तरह है:LINQ - समूह कई समूहों में आइटम के साथ

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

b एक अहस्ताक्षरित पूर्णांक है, जो एक मुखौटा (MyEnum झंडे के संयोजन) है। एक वस्तु जिसका अर्थ है दो बार अगर obj.a = first | third अभिव्यक्त किया जा सकता है और मैं उन्हें करने के लिए एक groupBy करने के लिए नहीं कर पा रहे -

अब मैं द्वारा हर वस्तु योग करने के लिए उनके a की जरूरत है। क्या उन्हें योग करने का एक अलग तरीका है?

मुझे खेद है कि मैं अपना कोड साझा नहीं करता, लेकिन मैं नहीं कर सकता। मैं आपको बता सकता है मैं इसे में foreach का उपयोग कर बस कुछ करता है, तो था - को अवरोधित कर देते लेकिन मुझे लगता है कि मैं कैसे Linq

में यह करने के लिए

संपादित सीखना चाहिए: मुझे लगता है कि मैं स्पष्ट नहीं था। मैं Enum द्वारा वस्तु योग करने के लिए चाहते हैं, जिसका अर्थ है यदि मेरे पास है:

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

तो उत्पादन होगा

first sum = 8 
second sum = 3 
+0

(एक डबल from एक SelectMany को संकलक द्वारा परिवर्तित किया जाता है) आप सकता है ने सुझाव दिया शायद SelectMany का उपयोग करने पर है अपेक्षित परिणाम प्रदान करें? आपका प्रश्न वास्तव में मुझे स्पष्ट नहीं है –

+0

आपकी समस्या अभी भी स्पष्ट नहीं है। क्या होगा यदि हमारे पास 'obj3 = first | है दूसरा | तीसरा; 'रकम क्या हैं? वे हो सकता है 'पहले योग = 15',' दूसरा योग = 8', 'तीसरे योग = 3',' चौथे योग = 7', 'पांचवें योग = 8',' छठे योग = 14'? –

+0

@किंगकिंग बिल्कुल। मैं enum मानों द्वारा योग करता हूं, इसलिए अगर किसी ऑब्जेक्ट में पहले स्थान पर है। दूसरा | तीसरा और 3 मान फ़ील्ड में 3 तो पहले, दूसरे और तीसरे –

उत्तर

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 अभिव्यक्ति enum मानों का योग के प्रत्येक मान के लिए वापस आ जाएगी।

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

ध्यान दें कि यह मूल्य 0 साथ MyEnum.fourth के लिए भी एक "पंक्ति" वापस आ जाएगी।

अभिव्यक्ति enum (Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()) के मूल्यों के साथ शुरू होता है और उसके बाद प्रत्येक मान के लिए यह mcs है कि मूल्यों का योग ही MyEnum (mcs.Where(q => q.MyEnum.HasFlag(p)).Sum(q => q.Value))

आप enum के मूल्यों से निकालना चाहते हैं कि उपयोग नहीं किया जाता:

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 (Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()) के मूल्यों के साथ शुरू होता है और फिर इसे "बचाता है" प्रत्येक मान के लिए mcs है कि मानों एक ही MyEnum (+०१२३१५८७८५४) temp में, temp छोड़ देता है जो खाली हैं (where temp.Length > 0) और शेष temp (select new { MyEnum = p, Sum = temp.Sum(q => q) }) को मिलाएं। ध्यान दें कि आप temp.Sum(q => q) उपयोग करने के लिए अगर आप एक uint उपयोग करें, लेकिन एक int साथ आप temp.Sum() उपयोग कर सकते हैं (या आप temp.Sum(q => q) उपयोग कर सकते हैं)।

एक और तरीका है एक डबल 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) }; 

यह रूप में ChaseMedallion

+0

वाह, वास्तव में धन्यवाद। बहुत समझाया और भविष्य के उपयोग के लिए भी अच्छा है। उत्कृष्ट उत्तर –

3

एक विशेष enum मूल्य के लिए सभी झंडे को निकालने के लिए 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

के योग में जोड़ा जाएगा, आपके उत्तर के लिए धन्यवाद, वास्तव में अच्छा है और समझाया, कोशिश करेंगे यथाशीघ्र है –

संबंधित मुद्दे