sennett
sennett

Reputation: 8444

Translate a bunch of booleans to a list of enums using LINQ

Say I have a class like this:

class From
{
    public bool FlagOne { get; set; }
    public bool FlagTwo { get; set; }
    public bool FlagThree { get; set; }
}

... and I want to convert a list of these into a list of these:

class To
{
    public List<Flag> Flags { get; set; }
}

... where Flag looks like this:

public enum Flag
{
    One,Two,Three
}

I write some code:

var froms = new List<From>
{
    new From {
        FlagOne = false,
        FlagTwo = true,
        FlagThree = true
    },
    new From {
        FlagOne = true,
        FlagTwo = false,
        FlagThree = true
    }
};

var tos = froms.Select(from => new To {
    Flags = // ....... what?  what goes here?
}).ToList();

The names of the enum values and the boolean flags to not matter. There should be no reflection necessary.

Context

I have a database table like this:

+---------+---------+-----------+
| FlagOne | FlagTwo | FlagThree | 
+=========+=========+===========|
|    0    |    1    |     1     |
+---------+---------+-----------+
|    1    |    0    |     1     |
+---------+---------+-----------+

and I want to make a UI that looks like this:

+-------------------------------------+
| Lorem blahdiblah FlagTwo, FlagThree |
+-------------------------------------+
| Lorem blahdiblah FlagOne, FlagThree |
+-------------------------------------+

I don't have to do this; I just thought it was an interesting problem to solve with LINQ, and couldn't find any answers.

Upvotes: 1

Views: 194

Answers (4)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726849

One way to deal with this is using nullable Flags in a collection, and then filter out the nulls, like this:

var tos = froms
    .Select(f => new To {
        Flags = new[] {
            f.FlagOne   ? (Flag?)Flag.One : null,
            f.FlagTwo   ? (Flag?)Flag.Two : null,
            f.FlagThree ? (Flag?)Flag.Three : null
        }
        .Where(f => f.HasValue)
        .Select(f => f.Value)
        .ToList()
     }).ToList();

The array created in the assignment of Flags has three items of type Flag? - one for each flag. The flags that correspond to an unset property become nulls; the flags corresponding to set properties become the nullable Flag.XYZ.

The rest is simple: the Where() filters out the nulls, the Select() drops nullability, and finally ToList() makes the results a list.

Upvotes: 3

Mason
Mason

Reputation: 721

It isn't clear exactly how you intend for the flag bools to map into enum values, but you would probably want to use something like this:

Flags = new List<Flag> { 
from.FlagOne ? Flag.One : Flag.Two,
from.FlagTwo ? Flag.One : Flag.Two,
from.FlagThree ? Flag.One : Flag.Two }

The main question being what you want Flag.One, Flag.Two, and Flag.Three to represent.

Upvotes: 0

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477230

Why do you want to convert it?

You can implement flags in Enums as well:

[Flags]
public enum Foo : int {
   Bit1 = 0x01,
   Bit2 = 0x02,
   Bit3 = 0x04
}

You can then check if a flag is active simply by a bitwise AND operation. For instance:

Foo aVariable = Foo.Bit1|Foo.Bit3;//both bit1 and bit3 are enabled

Check if bit3 is enabled:

if((aVariable&Foo.Bit3) != 0x00) {
   //flag is enabled, now do something
}
else {
   //flag is disabled, do something else
}

The advantage of using such constructions is that the bits are represented more compact, operations (like a bitwise OR) can be handled more faster and you don't have to worry about semantics of the bits (the enum hides the actual value of the bits).

If you really want to enumerate over the possible values, you can use a generic construction:

public static class Bar {

  public static IEnumerable<T> EnumerateAtoms<T> (this T input) where T : enum {
    foreach(T value in Enum.GetValues(typeof(T))) {
      if((input&val) != 0x00) {
        yield return value;
      }
    }
  }

}

Upvotes: 1

dtb
dtb

Reputation: 217351

To ConvertFromFromToTo(From from)
{
    List<Flag> flags = new List<Flag>();

    if (from.FlagOne)   flags.Add(Flag.One);
    if (from.FlagTwo)   flags.Add(Flag.Two);
    if (from.FlagThree) flags.Add(Flag.Three);

    return new To { Flags = flags };
}
var tos = froms.Select(ConvertFromFromToTo).ToList();

Upvotes: 0

Related Questions