2

I would like to choose the third element from an enum containing three elements while knowing which two I have already chosen. What is the most effcient way of comparing enums?

EDIT:

So far I have come up with the following:

Drawable.Row alternateChoice = (Drawable.Row)ExtensionMethods.Extensions.DefaultChoice(new List<int>() { (int)chosenEnum1, (int)chosenEnum2 }, new List<int>() { 0, 1, 2 });

Drawable.Row is the enum, the first list is what has already been chosen, and the second list contains the possible choices. The definition of DefaultChoice follows. I am aware it has quadratic time-complexity which is why I'm asking for a better solution:

public static int DefaultChoice(List<int> chosen, List<int> choices)
{
    bool found = false;
    foreach (int choice in choices)
    {
        foreach (int chosenInt in chosen)
        {
            if (chosenInt == choice)
            {
                found = true;
                break;
            }
        }
        if (!found)
        {
            return choice;
        }
        found = false;
    }
    return -1;
}
Jurgen Camilleri
  • 3,559
  • 20
  • 45
  • 3
    using == ........... – Mitch Wheat Feb 28 '13 at 00:20
  • 4
    Please show you "not so efficient" code so it can be improved/confirmed to be good. – Alexei Levenkov Feb 28 '13 at 00:25
  • I **disagree** with closing this as `Not a real question`. It's easy to tell what is being asked here. This question is not ambiguous, vague, incomplete or overly broad and can be reasonably answered in its current form. – Jeremy Thompson Feb 28 '13 at 00:43
  • What do you mean "third element"? Enum values don't have any ordering. Enums are just integral types: use `Enum.GetValues()` and enumerate over it. It gets more complex if the enum in question is decorated with the [Flags] attribute as you then have do deal with all the possible combinations. Also, don't forget that an enum may hold **any** value that will fit in its underlying type, simply by casting: `MyEnum foo = (MyEnum) 99999 ;` is perfectly valid, regardless of whether `MyEnum` maps a name to the value `99999`. – Nicholas Carey Feb 28 '13 at 00:47
  • I mean the element which remains after having chosen all but one of the possible values. – Jurgen Camilleri Feb 28 '13 at 00:52

3 Answers3

3

Try this:

List<MyEnum> selectedValues = new List<MyEnum>();
selectedValues.Add(MyEnum.firstValue); // Add selected value
selectedValues.Add(MyEnum.secondValue); // Add selected value

List<MyEnum> valuesLeftOver = Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().ToList();

valuesLeftOver = valuesLeftOver.Except(selectedValues).ToList<MyEnum>(); // This will result in the remaining items (third item) being in valuesLeftOver list.

Short and simple code.

Try not to worry about efficiency too much. Optimization algorithms are so powerful these days that you will probably get same assembly code doing this rather than trying to do it manually.

Daniel Wardin
  • 1,840
  • 26
  • 48
  • 1
    Yeah +1 - showing some sportsmanship. Your answer is `elegant` which is what the OP asked for, my way is more focused on `efficiency` – Jeremy Thompson Feb 28 '13 at 00:39
  • Thanks a lot @JeremyThompson! Real sportsman! Here is a vote up for the comprehensive answer and sportsmanship! – Daniel Wardin Feb 28 '13 at 00:42
  • I really like this solution, however since I'm on working on a Windows Phone application I don't have Enum.GetValues available :( – Jurgen Camilleri Feb 28 '13 at 00:50
  • Thank you very much! Have a look here for a method which can be used instead of Enum.GetValues(), you can try to copy that code and see if you can substitue that for Enum.GetValues() http://stackoverflow.com/questions/1038234/iterating-through-an-enumeration-in-silverlight Haven't tried it but it seems like it should work! – Daniel Wardin Feb 28 '13 at 00:53
2
[Flags]
public enum NumberEnum : byte
{
    None = 0,
    One = 1,
    Two = 2,
    Three = 4
};       

public string GetRemainingEnumItem(NumberEnum filterFlags = 0)
{  
 if (((filterFlags & NumberEnum.One) == NumberEnum.One) && ((filterFlags & NumberEnum.Two) == NumberEnum.Two))
 {
    //1 & 2 are selected so item 3 is what you want
 }

 if (((filterFlags & NumberEnum.One) == NumberEnum.One) && ((filterFlags & NumberEnum.Three) == NumberEnum.Three))
 {
    //1 & 3 are selected so item 2 is what you want
 }

 if (((filterFlags & NumberEnum.Three) == NumberEnum.Three) && ((filterFlags & NumberEnum.Two) == NumberEnum.Two))
 {
    //2 & 3 are selected so item 1 is what you want
 }
}

This is how you call it:

var testVal = NumberEnum.One | NumberEnum.Two;
var resultWillEqual3 = GetRemainingEnumItem(testVal);
Jeremy Thompson
  • 61,933
  • 36
  • 195
  • 321
1

You might like to try this approach...

public enum Marx {chico, groucho, harpo};

public Marx OtherOne(Marx x, Marx y)
{
  return (Marx)((int)Marx.chico + (int)Marx.groucho + (int)Marx.harpo - (int)x - (int)y);
} // OtherOne

// ...

Marx a = Marx.harpo;
Marx b = Marx.chico;
Marx other = OtherOne(a, b); // picks groucho

This may be of use if you are using an enum marked as [Flags]...

public class Enums2
{
  [Flags] public enum Bits {none = 0, aBit = 1, bBit = 2, cBit = 4, dBit = 8};
  public static readonly Bits allBits;

  static Enums2()
  {
    allBits = Bits.none;
    foreach (Bits b in Enum.GetValues(typeof(Bits)))
    {
      allBits |= b;
    }
  } // static ctor

  public static Bits OtherBits(Bits x)
  // Returns all the Bits not on in x
  {
    return x ^ allBits;
  } // OtherBits

  // ...

  Bits    someBits = Bits.aBit | Bits.dBit;
  Bits missingBits = OtherBits(someBits); // gives bBit and cBit

} // Enums2
Clive Tooth
  • 163
  • 9
  • Wow I really like this solution! Is there any way to make it scalable though? In events where you need the function for different numbers of elements in an enum you'd need to rewrite the function. – Jurgen Camilleri Mar 03 '13 at 22:45