考虑一下:
[Flags]
enum Colors
{
Red=1,
Green=2,
Blue=4
}
Colors myColor=Colors.Red|Colors.Blue;
目前,我的工作如下:
int length=myColors.ToString().Split(new char[]{','}).Length;
但我希望有一种更有效的方法来查找长度,可能基于bitset操作。
如果可能,请说明解决方案的原因和方式。
此外,如果这是重复,请指出它,我将删除此问题。关于我能够找到的唯一类似问题,关注的是找到Colors
枚举的所有可能组合的长度,而不是myColors
变量的长度。
更新:我仔细评估了每个解决方案(每个解决方案1 000 000次),结果如下:
Stevo3000是一个明显的赢家(马特埃文斯持有银牌)。
非常感谢你的帮助。
更新2: 该解决方案运行速度更快:100 000次迭代时间为41 ms(比Stevo3000快约40倍(32位操作系统))
UInt32 v = (UInt32)co;
v = v - ((v >> 1) & 0x55555555);
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
UInt32 count = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
答案 0 :(得分:10)
以下代码将为您提供为给定数量的任何类型设置的位数,其大小从字节到长度不等。
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;
}
这段代码非常有效,因为它只针对每个位迭代一次,而不是像其他示例那样针对每个可能的位迭代一次。
答案 1 :(得分:3)
以下是一些操作Flags
枚举的扩展方法:
public static class EnumExtensions
{
private static void CheckEnumWithFlags<T>()
{
if (!typeof(T).IsEnum)
throw new ArgumentException(string.Format("Type '{0}' is not an enum", typeof(T).FullName));
if (!Attribute.IsDefined(typeof(T), typeof(FlagsAttribute)))
throw new ArgumentException(string.Format("Type '{0}' doesn't have the 'Flags' attribute", typeof(T).FullName));
}
public static bool IsFlagSet<T>(this T value, T flag) where T : struct
{
CheckEnumWithFlags<T>();
long lValue = Convert.ToInt64(value);
long lFlag = Convert.ToInt64(flag);
return (lValue & lFlag) != 0;
}
public static IEnumerable<T> GetFlags<T>(this T value) where T : struct
{
CheckEnumWithFlags<T>();
foreach (T flag in Enum.GetValues(typeof(T)).Cast<T>())
{
if (value.IsFlagSet(flag))
yield return flag;
}
}
public static T SetFlags<T>(this T value, T flags, bool on) where T : struct
{
CheckEnumWithFlags<T>();
long lValue = Convert.ToInt64(value);
long lFlag = Convert.ToInt64(flags);
if (on)
{
lValue |= lFlag;
}
else
{
lValue &= (~lFlag);
}
return (T)Enum.ToObject(typeof(T), lValue);
}
public static T SetFlags<T>(this T value, T flags) where T : struct
{
return value.SetFlags(flags, true);
}
public static T ClearFlags<T>(this T value, T flags) where T : struct
{
return value.SetFlags(flags, false);
}
public static T CombineFlags<T>(this IEnumerable<T> flags) where T : struct
{
CheckEnumWithFlags<T>();
long lValue = 0;
foreach (T flag in flags)
{
long lFlag = Convert.ToInt64(flag);
lValue |= lFlag;
}
return (T)Enum.ToObject(typeof(T), lValue);
}
}
在您的情况下,您可以使用GetFlags
方法:
int count = myColors.GetFlags().Count();
它的效率可能不如Luke的答案,但它更容易使用...
答案 2 :(得分:2)
这是计算位数的一种相当简单的方法。每个位依次移位到Int64
的LSB,AND
- 用1表示(用于屏蔽掉任何其他位),然后添加到运行总计中。
int length = Enumerable.Range(0, 64).Sum(x => ((long)myColor >> x) & 1);
答案 3 :(得分:2)
这是我对此的看法...它计算值
中的设置位数int val = (int)myColor;
int count = 0;
while (val > 0)
{
if((val & 1) != 0)
{
count++;
}
val = val >> 1;
}
答案 4 :(得分:1)
假设它们是标志,您可以使用其中一种方法here来计算设置的位数。
这是有效的,因为只要它们是标志,当每一个都被“开启”时,它会设置一位。
- 编辑
使用该链接上的某个方法的示例代码:
[Flags]
enum Test
{
F1 = 1,
F2 = 2,
F3 = 4
}
class Program
{
static void Main(string[] args)
{
int v = (int) (Test.F1 | Test.F2 | Test.F3); // count bits set in this (32-bit value)
int c = 0; // store the total here
int[] S = {1, 2, 4, 8, 16}; // Magic Binary Numbers
int[] B = {0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF};
c = v - ((v >> 1) & B[0]);
c = ((c >> S[1]) & B[1]) + (c & B[1]);
c = ((c >> S[2]) + c) & B[2];
c = ((c >> S[3]) + c) & B[3];
c = ((c >> S[4]) + c) & B[4];
Console.WriteLine(c);
Console.Read();
}
}
答案 5 :(得分:1)
粗略近似将只计算myColors
中设置的位数,但只有在每个枚举成员的值为2的幂时才会起作用。
答案 6 :(得分:1)
我为自己做了一个辅助方法。也许这对其他人有用。
public static class EnumHelper
{
public static UInt32 NumFlags(this Enum e)
{
UInt32 v = Convert.ToUInt32(e);
v = v - ((v >> 1) & 0x55555555);
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
UInt32 count = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
return count;
}
}
答案 7 :(得分:0)
最可靠的解决方案是测试枚举中的每个值:
int len = 0;
foreach (Colors color in Enum.GetValues(typeof(Colors))) {
if ((myColor & color) == color) {
len++;
}
}
即使值设置了枚举中没有定义值的位,这也会起作用,例如:
Colors myColor = (Colors)65535;
这也适用于使用多个位的值的枚举:
[Flags]
enum Colors {
Red = 0xFF0000,
Green = 0x00FF00,
Blue = 0x0000FF
}
答案 8 :(得分:0)
int value = Enum.GetNames(typeof(Colors)).Length;
public static int NumberOfOptions(int value)
{
int result = (int)Math.Pow(2, value-1);
return result;
}
答案 9 :(得分:-3)
试试这个......
Colors.GetValues().Length();
......还是太明显了?
编辑:
好的,我刚刚再次阅读了这个问题,并意识到你需要'mycolors'的长度,而不是'Colors' - 让我想一想。
进一步编辑:
现在我很困惑 - OP发布的解决方案永远不会起作用,因为myColor.ToString()返回'5'并将Split(new char [] {','})应用于此将导致一个数组带有长度为1。 OP实际上是否可以使用它?