我如何获得一个枚举标记的所有可能的组合

如何解决我如何获得一个枚举标记的所有可能的组合

|
[Flags]
public enum MyEnum
{
    None = 0,Setting1 = (1 << 1),Setting2 = (1 << 2),Setting3 = (1 << 3),Setting4 = (1 << 4),}
我需要能够以某种方式遍历每个可能的设置,并将设置组合传递给函数。可悲的是我一直无法弄清楚该怎么做     

解决方法

未经测试,使用风险自负,但应一般地解决此问题。
System.Enum
不是有效的限制,因为从技术上讲,C#仅允许在with2ѭ中进行继承或在
class
中进行继承,后端绕过
Enum
ValueType
。对不起,我的丑陋铸造。它也不是非常有效,但是除非您针对动态生成的类型运行它,否则每次执行仅应执行一次(如果保存,则必须执行一次)。
public static List<T> GetAllEnums<T>()
    where T : struct
    // With C# 7.3 where T : Enum works
{
    // Unneeded if you add T : Enum
    if (typeof(T).BaseType != typeof(Enum)) throw new ArgumentException(\"T must be an Enum type\");

    // The return type of Enum.GetValues is Array but it is effectively int[] per docs
    // This bit converts to int[]
    var values = Enum.GetValues(typeof(T)).Cast<int>().ToArray();

    if (!typeof(T).GetCustomAttributes(typeof(FlagsAttribute),false).Any())
    {
        // We don\'t have flags so just return the result of GetValues
        return values;
    }

    var valuesInverted = values.Select(v => ~v).ToArray();
    int max = 0;
    for (int i = 0; i < values.Length; i++)
    {
        max |= values[i];
    }

    var result = new List<T>();
    for (int i = 0; i <= max; i++)
    {
        int unaccountedBits = i;
        for (int j = 0; j < valuesInverted.Length; j++)
        {
            // This step removes each flag that is set in one of the Enums thus ensuring that an Enum with missing bits won\'t be passed an int that has those bits set
            unaccountedBits &= valuesInverted[j];
            if (unaccountedBits == 0)
            {
                result.Add((T)(object)i);
                break;
            }
        }
    }

    //Check for zero
    try
    {
        if (string.IsNullOrEmpty(Enum.GetName(typeof(T),(T)(object)0)))
        {
            result.Remove((T)(object)0);
        }
    }
    catch
    {
        result.Remove((T)(object)0);
    }

    return result;
}
通过获取所有值并将它们进行“或”运算,而不是求和,以防万一包含复合数字。然后,它将每个整数取到最大,并用每个Flag的相反值对其进行屏蔽,这使有效位变为0,从而使我们能够识别那些不可能的位。 最后的检查是从枚举中缺少零。如果可以,只要在结果中始终包含零枚举,就可以删除它。 给定包含2,4,6,32,34,16384的枚举时,得到15的预期结果。     ,这是您的代码示例特有的解决方案,使用简单的for循环(请勿使用,请参见下面的更新)
int max = (int)(MyEnum.Setting1 | MyEnum.Setting2 | MyEnum.Setting3 | MyEnum.Setting4);
for (int i = 0; i <= max; i++)
{
    var value = (MyEnum)i;
    SomeOtherFunction(value);
}
更新:这是一个通用方法,将返回所有可能的组合。还要感谢@David Yaw提出使用队列来构建每个组合的想法。
IEnumerable<T> AllCombinations<T>() where T : struct
{
    // Constuct a function for OR-ing together two enums
    Type type = typeof(T);
    var param1 = Expression.Parameter(type);
    var param2 = Expression.Parameter(type);
    var orFunction = Expression.Lambda<Func<T,T,T>>(
        Expression.Convert(
            Expression.Or(
                Expression.Convert(param1,type.GetEnumUnderlyingType()),Expression.Convert(param2,type.GetEnumUnderlyingType())),type),param1,param2).Compile();

    var initalValues = (T[])Enum.GetValues(type);
    var discoveredCombinations = new HashSet<T>(initalValues);
    var queue = new Queue<T>(initalValues);

    // Try OR-ing every inital value to each value in the queue
    while (queue.Count > 0)
    {
        T a = queue.Dequeue();
        foreach (T b in initalValues)
        {
            T combo = orFunction(a,b);
            if (discoveredCombinations.Add(combo))
                queue.Enqueue(combo);
        }
    }

    return discoveredCombinations;
}
    ,
    public IEnumerable<TEnum> AllCombinations<TEnum>() where TEnum : struct
    {
        Type enumType = typeof (TEnum);
        if (!enumType.IsEnum)
            throw new ArgumentException(string.Format(\"The type {0} does not represent an enumeration.\",enumType),\"TEnum\");

        if (enumType.GetCustomAttributes(typeof (FlagsAttribute),true).Length > 0) //Has Flags attribute
        {
            var allCombinations = new HashSet<TEnum>();

            var underlyingType = Enum.GetUnderlyingType(enumType);
            if (underlyingType == typeof (sbyte) || underlyingType == typeof (short) || underlyingType == typeof (int) || underlyingType == typeof (long))
            {
                long[] enumValues = Array.ConvertAll((TEnum[]) Enum.GetValues(enumType),value => Convert.ToInt64(value));
                for (int i = 0; i < enumValues.Length; i++)
                    FillCombinationsRecursive(enumValues[i],i + 1,enumValues,allCombinations);
            }
            else if (underlyingType == typeof (byte) || underlyingType == typeof (ushort) || underlyingType == typeof (uint) || underlyingType == typeof (ulong))
            {
                ulong[] enumValues = Array.ConvertAll((TEnum[]) Enum.GetValues(enumType),value => Convert.ToUInt64(value));
                for (int i = 0; i < enumValues.Length; i++)
                    FillCombinationsRecursive(enumValues[i],allCombinations);
            }
            return allCombinations;
        }
        //No Flags attribute
        return (TEnum[]) Enum.GetValues(enumType);
    }

    private void FillCombinationsRecursive<TEnum>(long combination,int start,long[] initialValues,HashSet<TEnum> combinations) where TEnum : struct
    {
        combinations.Add((TEnum)Enum.ToObject(typeof(TEnum),combination));
        if (combination == 0)
            return;

        for (int i = start; i < initialValues.Length; i++)
        {
            var nextCombination = combination | initialValues[i];
            FillCombinationsRecursive(nextCombination,initialValues,combinations);
        }
    }

    private void FillCombinationsRecursive<TEnum>(ulong combination,ulong[] initialValues,combinations);
        }
    }
    ,首先,获取所有单个值的列表。由于您有5个值,因此
(1 << 5)
= 32个组合,因此从1到31进行迭代。(不要从零开始,这意味着不包含任何枚举值。)进行迭代时,请检查数字中的位,迭代变量中的每一位都意味着要包含该枚举值。将结果放入HashSet中,以确保没有重复项,因为包含\'None \'值不会更改结果枚举。
List<MyEnum> allValues = new List<MyEnum>(Enum.Getvalues(typeof(MyEnum)));
HashSet<MyEnum> allCombos = new Hashset<MyEnum>();

for(int i = 1; i < (1<<allValues.Count); i++)
{
    MyEnum working = (MyEnum)0;
    int index = 0;
    int checker = i;
    while(checker != 0)
    {
        if(checker & 0x01 == 0x01) working |= allValues[index];
        checker = checker >> 1;
        index++;
    }
    allCombos.Add(working);
}
    ,由于它是一个标记的枚举,所以为什么不简单: 获得枚举的最高值。 计算组合的范围,即上限。 迭代每个组合,即从0循环到上限。 一个例子看起来像这样
var highestEnum = Enum.GetValues(typeof(MyEnum)).Cast<int>().Max();
var upperBound = highestEnum * 2;    
for (int i = 0; i < upperBound; i++)
{
    Console.WriteLine(((MyEnum)i).ToString());
}
    ,当我向枚举添加新成员时,我通常不希望更新表示枚举最大值的每个变量。 例如,我不喜欢格雷格提出的声明:
int max = (int)(MyEnum.Setting1 | MyEnum.Setting2 | ... | MyEnum.SettingN);
考虑一下当您在整个解决方案中散布着几个可变符时,您决定修改枚举。这肯定不是理想的情况。 我会事先承认我的代码较慢,但是在修改枚举后它会自动正确,并且我会努力以这种健壮的方式进行编码。我愿意为此付出一些计算上的损失,反正C#就是这样。我提议:
public static IEnumerable<T> GetAllValues<T>() where T : struct
{
    if (!typeof(T).IsEnum) throw new ArgumentException(\"Generic argument is not an enumeration type\");
    int maxEnumValue = (1 << Enum.GetValues(typeof(T)).Length) - 1;
    return Enumerable.Range(0,maxEnumValue).Cast<T>();
}
假设枚举包含2的所有幂直到特定幂(包括0)的成员,就像通常使用标志枚举一样。     ,我可能要晚一点,我想离开我的解决方案,该解决方案还包括值以及以(\“ V1 | V2 \”,\“ V1 | V2 | V3 \ ”等)。 我采用了上面提出的解决方案的某些方面,因此,感谢所有发布了先前答案的人:D。 注意:仅适用于将Enum设置为以2为基数的组合的情况。
public static Dictionary<int,string> GetCombinations( this Enum enu)
    {
        var fields = enu.GetType()
                        .GetFields()
                        .Where(f => f.Name != \"value__\")
                        .DistinctBy(f=> Convert.ToInt32(f.GetRawConstantValue()));

        var result = fields.ToDictionary(f=>Convert.ToInt32(f.GetRawConstantValue()),f => f.Name);

        int max = Enum.GetValues(enu.GetType()).Cast<int>().Max();
        int upperBound = max * 2;

        for (int i = 0 ; i <= upperBound ; i += 2)
        {
            string s = Convert.ToString(i,2).PadLeft(Math.Abs(i-max),\'0\');
            Boolean[] bits = s.Select(chs => chs == \'1\' ? true : false)
                             .Reverse()
                             .ToArray();

            if (!result.ContainsKey(i))
            {
                var newComb = string.Empty;
                for (int j = 1; j < bits.Count(); j++)
                {
                    var idx = 1 << j;
                    if (bits[j] && result.ContainsKey(idx))
                    {
                        newComb = newComb + result[idx] + \" | \";
                    }
                }                                      
                newComb = newComb.Trim(new char[] { \' \',\'|\' });
                if (!result.ContainsValue(newComb) && !string.IsNullOrEmpty(newComb))
                {
                    result.Add(i,newComb);
                }                    
            }
        }
        return result;
    }
    ,此版本的结论: 没有检查:
public IEnumerable<T> AllCombinations<T>() where T : struct
{
    var type = typeof(T);
    for (var combination = 0; combination < Enum.GetValues(type).Cast<int>().Max()*2; combination++)
    {
        yield return (T)Enum.ToObject(type,combination);
    }
}
经过一些检查:
public IEnumerable<T> AllCombinations<T>() where T : struct
{
    var type = typeof(T);
    if (!type.IsEnum)
    {
        throw new ArgumentException($\"Type parameter \'{nameof(T)}\' must be an Enum type.\");
    }

    for (var combination = 0; combination < Enum.GetValues(type).Cast<int>().Max()*2; combination++)
    {
        var result = (T)Enum.ToObject(type,combination);

        // Optional check for legal combination.
        // (and is not necessary if all flag a ascending exponent of 2 like 2,8...
        if (result.ToString() == combination.ToString() && combination != 0)
        {
            continue;
        }

        yield return result;
    }
}
    

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-