C# 枚举 - 给定一个 int 输入猜测标志

C# Enum - Guessing Flags given an int input

假设我们有以下标志枚举:

[Flags]
    public enum Animals
    {
        Cow = 1,

        Duck = 2,

        Goose = 4
    }

现在,给定这个枚举,我们想要指定一个函数,将 int 作为输入,给定这个数字,我们想要 return 一个包含这个数字包含的动物的数组。

例如,如果我们收到数字 7 作为输入,我们就知道我们有奶牛、鸭子和鹅,因为 4+2+1 = 7。

对于此枚举中出现的任意数量的动物,我们如何确定该数量中包含哪些动物?

public static IEnumerable<Animals> GetAnimals(int i)
{
    var animals = (Animals) i;

    foreach (Enum value in Enum.GetValues(animals.GetType()))
        if (animals.HasFlag(value))
            yield return (Animals) value;
}

Fiddle: https://dotnetfiddle.net/yydUE2

通用版本 - 不是太快,可能会有所改进...

void Main()
{
    var flags = Ext.GetFlags<Animal>(7);
    flags.Dump();
}

public static class Ext
{
    public static IEnumerable<T> GetFlags<T>(int flags)
    where T : struct    
    {
        return typeof(T).GetEnumValues().Cast<T>()
            .Where(a => ((dynamic)(T)(object)flags).HasFlag(a)).ToList();
    }
}

[Flags]
public enum Animal
{
    Cow =1,
    Duck = 2,
    Goose = 4,
    Dog = 8
}

正如其他人所说,绝大多数情况下没有单一的答案,但举个例子,我假设你想要一个贪婪的猜测算法来 return 大值动物的最小数量:

void Main()
{

    int test = 21;

    var allAnimals = (Animal[]) Enum.GetValues(typeof(Animal));
    var ordered = allAnimals.OrderByDescending(x => x);

    var animals = ordered.Aggregate(new List<Animal>(), (agg, ani) => { 
        if (test > 0) {
            int number = (int)(test / (int)ani);
            agg.AddRange(Enumerable.Repeat(ani, number));
            test -= number * (int)ani;
        }
        return agg;
    });

    Console.WriteLine(string.Join(", ", animals.Select(a=>a.ToString())));
}

[Flags]
public enum Animal
{
    Cow = 1,

    Duck = 2,

    Goose = 4
}