Counting the number of flags set on an enumeration

2020-07-02 08:24发布

I'm sure there must be a much better way of doing this. I'm trying to do a count operation on a Flags enum. Before I was itterating over all the possible values and counting the succesful AND operations.

e.g.

[Flags]
public enum Skills
{
    None = 0,
    Skill1 = 1,
    Skill2 = 2,
    Skill3 = 4,
    Skill4 = 8,
    Skill5 = 16,
    Skill6 = 32,
    Skill7 = 64,
    Skill8 = 128
}

public static int Count(Skills skillsToCount)
{
   Skills skill;
   for (int i = 0; i < SkillSet.AllSkills.Count; i++)
   {
      skill = SkillSet.AllSkills[i];
      if ((skillsToCount & skill) == skill && skill != Skills.None)
         count++;
   }
   return count;
}

I'm sure there must be a better way of doing this though, but must be suffering from a mental block. Can anyone advise a nicer solution?

标签: c# enums
9条回答
迷人小祖宗
2楼-- · 2020-07-02 09:19

There's a straight-forward way using functional programming (LINQ):

var skillCount = Enum
    .GetValues(typeof(Skills))
    .Cast<Enum>()
    .Count(skills.HasFlag);

It might be a bit slower than the bit-juggling solutions, but it's still allocation-free, has a constant run-time and is more intuitive.

查看更多
再贱就再见
3楼-- · 2020-07-02 09:21

The following code will give you the number of bits that are set for a given number of any type varying in size from byte up to long.

public static int GetSetBitCount(long lValue)
{
  int iCount = 0;

  //Loop the value while there are still bits
  while (lValue != 0)
  {
    //Remove the end bit
    lValue = lValue & (lValue - 1);

    //Increment the count
    iCount++;
  }

  //Return the count
  return iCount;
}

This code is very efficient as it only iterates once for each bit rather than once for every possible bit as in the other examples.

查看更多
唯我独甜
4楼-- · 2020-07-02 09:26
<FlagsAttribute()> _
Public Enum Skills As Byte
    None = 0
    Skill1 = 1
    Skill2 = 2
    Skill3 = 4
    Skill4 = 8
    Skill5 = 16
    Skill6 = 32
    Skill7 = 64
    Skill8 = 128
End Enum


    Dim x As Byte = Skills.Skill4 Or Skills.Skill8 Or Skills.Skill6
    Dim count As Integer
    If x = Skills.None Then count = 0 Else _
        count = CType(x, Skills).ToString().Split(New Char() {","c}, StringSplitOptions.RemoveEmptyEntries).Count

depends on the definition of "better".

the check for Skills.None is required because if no bits are on, the string() returns Skills.None which results in a count of 1. this would work the same for integer, long, and their unsigned relatives.

查看更多
登录 后发表回答