views:

348

answers:

7

I have enum like this

[Flags]
public enum Key
{
  None = 0,
  A = 1,
  B = 2,
  C = 4
}

I have the following

Key k1 = Key.A | Key.B | Key.C;

I want to get the key in k1 that has the lowest value. How can I do that?

Example:

Key k1 = Key.A | Key.B | Key.C; // I want a 
Key k2 = Key.B | Key.C; // I want b
Key k3 = Key.A | Key.C; // I want a
A: 

If you have only 3 values in the enum probably the fastest and easiest is to check them one by one. For a general solution, however, you might want to try to convert the value of k1 to integer, find the largest power of 2 that divides it and convert it back to Keys enum value.

Thomas Wanner
A: 
  1. Get a list of all the values in the enum
  2. Map those values to some kind of comparable data type
  3. Compare all the values and keep track of the lowest one
  4. Convert the lowest one back to the enum type
NickLarsen
+4  A: 
Keys key = Keys.b | Keys.c;

var lowest = Enum.GetValues(typeof(Keys))
    .OfType<Keys>()
    .Where(x => (x & key) != 0)
    .OrderBy(x => x)
    .DefaultIfEmpty((Keys)0);

Console.WriteLine(lowest);
David Morton
Oh my, I love this.
Jason
I guess you should add something like `.DefaultIfEmpty((Keys)0)` before first, so it doesn't throw an exception if key is 0.
Mark Byers
Great idea, thanks! Done.
David Morton
+10  A: 

You can use a bit trick:

Key key = Key.B | Key.C;
Key lowest = (Key)((int)key & -(int)key);
Mark Byers
I really like this. Well done.
David Morton
@David: Personally, I think it's almost unreadable. It's an interesting curiousity but I hope no-one actually uses it in production code! I'd prefer to use one of the LINQ methods. If someone does use this, I hope they at least comment it with an explanation of what it is doing.
Mark Byers
Yeah, it takes a bit to get it, but I can pretty much guarantee you it's the fastest, and it's so concise. It's certainly a trade-off readability vs efficiency. That being said, I'd probably put something like this in, and then forget what I did later on down the line. Nevertheless, it's pretty cool if you're simply talking about the geekiness factor.
David Morton
Well done. Brilliant!
Vivek
A: 

Needs to be an iterative implementation where you test bits. I would do something like this.

unsigned int k = (unsigned int) k1;
int pos = -1;
while (k) {
   pos++;
   if (k & 0x1) break;
   k >>= 1;
}
Keys lowestKey = 0;
if (pos >= 0) lowestKey = 0x1 << pos;
don
A: 

The code you originally posted doesn't make sense: a+b+c aren't prefixed by a type-name, so they won't refer to the enum names they seem to be intended to refer to.

Also, if you use a bitwise AND to combine flags, the result will contain all flags on in all paramters - in this case, none.

Eamon Nerbonne
+3  A: 
Keys key = Keys.b | Keys.c;

var lowest = Enum.GetValues(typeof(Keys))
    .Cast<Keys>()
    .OrderBy(x => x)
    .FirstOrDefault(x => key.HasFlag(x));

Slightly more efficient and .NET 4.0-ish version of the LINQ method.

MikeP