Counting the number of flags set on an enumeration

后端 未结 9 1308
孤街浪徒
孤街浪徒 2021-02-18 20:17

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 t

相关标签:
9条回答
  • 2021-02-18 20:56

    A very concise way to do it using BitArray and LINQ:

    public static int Count(Skills skillsToCount)
    {
        return new BitArray(new[] {(int)skillsToCount}).OfType<bool>().Count(x => x);
    }
    
    0 讨论(0)
  • 2021-02-18 20:59

    If you're targeting .NET Core 3.0 or above, you can use BitOperations.PopCount(), it operates in uint or ulong and returns the number of 1 bits.

    If your CPU supports SSE4, it'll use the POPCNT CPU instruction, otherwise it'll use a software fallback.

    public static int Count(Skills skillsToCount)
    {
       return BitOperations.PopCount((ulong)skillsToCount);
    }
    
    0 讨论(0)
  • 2021-02-18 21:00

    the only reason to use this method is if the flags are not contiguous and if flags will be added periodically.

    <FlagsAttribute()> _
    Public Enum Skills As Integer
        Skill1 = CInt(2 ^ 0) 'bit 0
        Skill2 = CInt(2 ^ 1)
        Skill3 = CInt(2 ^ 2)
        Skill4 = CInt(2 ^ 3)
        Skill5 = CInt(2 ^ 4)
        Skill6 = CInt(2 ^ 5)
        Skill7 = CInt(2 ^ 6)
        Skill8 = CInt(2 ^ 7)
        Skillx = CInt(2 ^ 10) 'bit 10, some bits were skipped
    End Enum
    
    
        Dim mySkills As Integer = Skills.Skillx Or Skills.Skill4 Or Skills.Skill8 Or Skills.Skill6
        Dim count As Integer 'count of bits on
        count = CType(mySkills, Skills).ToString().Split(New Char() {","c}, _
                                                         StringSplitOptions.RemoveEmptyEntries).Count
    

    if "better" means faster this ain't ;) it.

    0 讨论(0)
  • 2021-02-18 21:03

    The count is equivalent to counting how many bits are set to 1 in the integer value of the enum.

    There are very fast ways of doing this in C/C++, which you can adapt to C#:

    e.g.

    int bitcount(unsigned int n) {
       /* works for 32-bit numbers only    */
       /* fix last line for 64-bit numbers */
    
       register unsigned int tmp;
    
       tmp = n - ((n >> 1) & 033333333333)
               - ((n >> 2) & 011111111111);
       return ((tmp + (tmp >> 3)) & 030707070707) % 63;
    }
    

    Taken from here.

    EDIT
    Provided link is dead. Found another one that probably contains the same content.

    0 讨论(0)
  • 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.

    0 讨论(0)
  • 2021-02-18 21:06

    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.

    0 讨论(0)
提交回复
热议问题