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
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);
}
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);
}
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.
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.
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.
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.