0

Consider the following Enum:

Enum AnimalType
{
  Dog = 1,
  Cat = 2,
  Bird = 4,
  Wolf = 8
} 

Now suppose we want to find all possible flag combinations where Dog is active, for example.

I divised the following method to do this:

public static int[] testss(int value)
    {
        var animalTypes = (AnimalType)value;
        List<int> possibleValues = new List<int>();
        possibleValues.Add(value);

        int totalEnumValues = Enum.GetNames(typeof(AnimalType)).Length;
        List<int> helper = new List<int>();
        int cnt = 0;

        for (int i = 1; i < totalEnumValues; i++)
        {
            foreach (Enum val in Enum.GetValues(animalTypes.GetType()))
            {
                if (cnt >= i)
                    break;

                if (i == 1)
                {
                    if ((AnimalType)val != (AnimalType)value)
                    {
                        possibleValues.Add((int)(AnimalType)val + value);
                    }
                }
                else
                {                        
                    if ((AnimalType)val != (AnimalType)value && (cnt < i))
                    {
                        helper.Add((int)(AnimalType)val);
                        cnt += 1;
                    }                        
                }
            }

            if (cnt > 0)
            {
                possibleValues.Add(helper.Sum() + value);

                helper = new List<int>();
                cnt = 0;
            }
        }         

        return possibleValues.ToArray();
    }

This method will build an array with all the possible numeric representations containing a given flag as input.

It works only partially, if you test it for Dog (1) for example, you'll see that 2 values are missing from the possibleValues array.

Can you help me realizing where I went wrong?

Hallaghan
  • 1,910
  • 6
  • 32
  • 47
  • Out of interest, why are you doing this? – Baldrick Jun 22 '15 at 09:42
  • How about taking all uneven numbers < 16? – TGlatzer Jun 22 '15 at 09:44
  • @Baldrick, To search and process entries given their active flags. They are stored in the database with their numeric representation (for instance, 15) and I need to know, for a given flag, all possible numeric representations to fetch from the DB and process. – Hallaghan Jun 22 '15 at 09:45
  • 1
    Take the binary representation and use logical AND with the binary representation of the given flag. If it's not zero, you are looking for it. – TGlatzer Jun 22 '15 at 09:48
  • 1
    Do you have control over the DB? If so, might be easier to add a stored proc that will return what you want. Otherwise, you're doing dozens of DB queries when the work would be better done DB-side. – Baldrick Jun 22 '15 at 09:49
  • Where is `statementTypes` defined? – DGibbs Jun 22 '15 at 09:49
  • @DGibbs, code edited (leftovers when masking my original variables) – Hallaghan Jun 22 '15 at 09:51
  • @Baldrick, I have no control over the DB, I have to do it this way. – Hallaghan Jun 22 '15 at 09:52
  • This seems to be a problem of calculating all the possible combinations and then filtering from them... http://stackoverflow.com/q/7802822/613130 Clearly it could be optimized to pre-skip the combinations not containing the chosen flag, but post-filtering is easier. – xanatos Jun 22 '15 at 09:55
  • 1
    Why you can't use bitwise operators in your query to database? – Oleg Jun 22 '15 at 10:05

2 Answers2

2

You could use the [Flags] enum attribute, then an extension method. Something like this:

[Flags]
enum AnimalType
{
  Dog = 1,
  Cat = 2,
  Bird = 4,
  Wolf = 8
} 

static class Program
{
    static void Main(string[] args)
    {
        var test = AnimalType.Dog.AllContaining();
    }

    public static int[] AllContaining(this AnimalType thisAnimal)
    {
        List<int> retVal = new List<int>();
        var possibleEnums = Enum.GetValues(typeof(AnimalType)).Length;
        var maxValue = (int)Math.Pow(2, possibleEnums);

        for (int i = 0; i < maxValue; i++)
        {
            if (((AnimalType)i).HasFlag(thisAnimal))
            {
                retVal.Add(i);
            }
        }
        return retVal.ToArray();
    }
}

It spins through all possible integer values of the enum, and sees if the 'flag' for the supplied animal is present. If it is, it adds to the return array.

Baldrick
  • 11,712
  • 2
  • 31
  • 35
  • in the end the solution was less complicated than I had imagined it. Thanks for showing me the way! – Hallaghan Jun 22 '15 at 11:11
  • 1
    You're welcome. You can probably improve on the `Math.Pow` bit by looking at the other answer. The Max() * 2 approach is cleaner, i.m.o. – Baldrick Jun 22 '15 at 11:27
1

Assuming there's not a lot of enum values, you can try:

        private static void Main(string[] args)
        {
            var type = AnimalType.Wolf;

            foreach (var x in GetAllPossibleCombinationWith(type))
            {
                Console.WriteLine(x);
            }


            Console.ReadLine();
        }


        public static IEnumerable<AnimalType> GetAllPossibleCombinationWith(AnimalType type) // Bird
        {
            var maxValue = Enum.GetValues(typeof(AnimalType)).Cast<int>().Max();
            var combinationValue =2* maxValue - 1;
            for (int i = 0; i < combinationValue; i++)
            {
                var val = (AnimalType) i;
                if ((val & type) == type) yield return val;
            }
        }

        [Flags]
        public enum AnimalType
        {
            Dog = 1,
            Cat = 2,
            Bird = 4,
            Wolf = 8,
            Fish = 16
        }

It assumes there's no "hole" in the flags values.

Steve B
  • 36,818
  • 21
  • 101
  • 174