2

Let's say I have

[Flags]
public enum MyEnum
{
   ValueZero = 1,
   ValueOne = 2,
   ValueTwo = 4
}

public class MyClass
{
   public string Property { get; set; }
   public MyEnum EnumValue { get; set; }
}

I'd want to be able to use GroupBy on a List<MyClass> to group by enums without considering that it is a flag enum.

When I use GroupBy (example at the end of the question), the groupings are made with the aggregated enums like this

//Grouping             Values
ValueZero | ValueOne : myClass1, myClass2
ValueOne  | ValueTwo : myClass3, myClass4 

I'm looking to get the following (using the GroupBy method because it is more performant than using Where 3 times)

//Grouping  Values
ValueZero : myClass1, myClass2
ValueOne  : myClass1, myClass2, myClass3, myClass4
ValueTwo  : myClass4

I thought using this would work :

var list = new List<MyClass>();
var groupedList = list.GroupBy(c => c.EnumValue);
IEatBagels
  • 823
  • 2
  • 8
  • 23

2 Answers2

2

Start by splitting each enum value into individual flags (like shown here), then flatten the results and group.

It should look like this:

var groupedList = list
    .Select(c => new { Flags=GetFlags(c.EnumValue), Item=c }) // split flags
    .SelectMany(c => c.Flags.Select(x => new { Flag=x, Item=c.Item })) // flatten
    .GroupBy(c => c.Flag, i => i.Item); // group

where GetFlags is a method which gets individual enum flags, like the method in the linked answer:

static IEnumerable<MyEnum> GetFlags(MyEnum input)
{
    return Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()
       .Where(f => input.HasFlag(f));
}
Community
  • 1
  • 1
vgru
  • 49,838
  • 16
  • 120
  • 201
1

If I guess your intention than in code it has an implementation like this:

var list = new List<MyClass>();
list.Add(new MyClass() {
   EnumValue = MyEnum.ValueZero | MyEnum.ValueOne, Property = "myClass1"
});
list.Add(new MyClass() {
   EnumValue = MyEnum.ValueZero | MyEnum.ValueOne, Property = "myClass2"
});
list.Add(new MyClass() {
   EnumValue = MyEnum.ValueOne , Property = "myClass3"
});
list.Add(new MyClass() {
   EnumValue = MyEnum.ValueOne | MyEnum.ValueTwo, Property = "myClass4"
});

var enumValues = Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().ToArray();
var grouped = list.SelectMany(
      o => enumValues
         .Where(flag => o.EnumValue.HasFlag(flag))
         .Select(v => new { o, v })
   )
   .GroupBy(t => t.v, t => t.o);

foreach (IGrouping<MyEnum, MyClass> group in grouped)
{                
   Console.WriteLine(group.Key.ToString() + ": " + string.Join(", ", group.Select(x=>x.Property)));
}
apros
  • 2,848
  • 3
  • 27
  • 31