计算枚举上设置的标志数量
我确信一定有更好的方法来做到这一点。 我正在尝试对 Flags 枚举进行计数操作。 在我遍历所有可能的值并计算成功的 AND 操作之前。
例如,
[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 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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
以下代码将为您提供为大小从字节到长的任何类型的给定数量设置的位数。
该代码非常高效,因为它只对每个位迭代一次,而不是像其他示例中那样对每个可能的位迭代一次。
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.
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.
在查看 Assaf 建议的网站后,我设法找到了一个与 Int32 工作略有不同的解决方案。
这是其他人的代码:
After looking on the site Assaf suggested I managed to find a slightly different solution that I got working for Int32's.
Here's the code for anyone else:
使用 BitArray 和 LINQ 的一种非常简洁的方法:
A very concise way to do it using
BitArray
and LINQ:如果您的目标是 .NET Core 3.0 或更高版本,则可以使用
BitOperations.PopCount()
,以uint
或ulong
进行操作,返回数量1
位。如果您的 CPU 支持 SSE4,它将使用
POPCNT
CPU 指令,否则它将使用软件回退。If you're targeting .NET Core 3.0 or above, you can use
BitOperations.PopCount()
, it operates inuint
orulong
and returns the number of1
bits.If your CPU supports SSE4, it'll use the
POPCNT
CPU instruction, otherwise it'll use a software fallback.计数相当于计数枚举的整数值中有多少位被设置为 1。
在 C/C++ 中有非常快速的方法可以做到这一点,您可以将其适应 C#:
例如
取自 此处。
编辑
提供的链接已失效。 发现另一个可能包含相同的内容。
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.
Taken from here.
EDIT
Provided link is dead. Found another one that probably contains the same content.
有一种使用函数式编程 (LINQ) 的直接方法:
它可能比位处理解决方案慢一点,但它具有恒定的运行时间并且更直观。
虽然 GetValues 仍在分配,但编译器很可能会对其进行优化。
There's a straight-forward way using functional programming (LINQ):
It might be a bit slower than the bit-juggling solutions but it has a constant run-time and is more intuitive.
While GetValues still allocates, there is a good chance that the compiler optimizes this away.
取决于“更好”的定义。
需要检查 Skills.None,因为如果没有位打开,则 string() 返回 Skills.None,这会导致计数为 1。这对于整数、长整型及其无符号亲属的工作方式相同。
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.
使用此方法的唯一原因是标志不连续并且标志是否会定期添加。
如果“更好”意味着更快,那不是;)它。
the only reason to use this method is if the flags are not contiguous and if flags will be added periodically.
if "better" means faster this ain't ;) it.