C# Flags - Getting all possible combinations where a given flag can be present

1.6k views Asked by At

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?

2

There are 2 answers

2
Baldrick On BEST ANSWER

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.

0
Steve B On

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.