2012-03-12 38 views
11

我的问题的关键部分是跳过。我打算使用大约20个元素的枚举类型。我想遍历这个集合,但每次都需要跳过一个或两个元素。事先知道要跳过什么。一个可比较的例子是枚举类型,它由字母表中的所有字母组成,迭代时,我想跳过所有的元音。如何遍历枚举类型,同时跳过一些值?

我应该如何以优雅/有效的方式编码迭代?我应该制作一组由元音组成的独立元素吗?我没有代码可以显示,因为我只是在想这个问题。

回答

27
var query = Enum.GetValues(typeof(MyEnum)) 
    .Cast<MyEnum>() 
    .Except(new MyEnum[] { MyEnum.A, MyEnum.E }); 
foreach (MyEnum item in query) { 
    ... 
} 

你需要为了得到LINQ的魔法施放。 Except一个人不会这样做。


UPDATE:

我有另一个想法。您可以使用FlagsAttribute定义枚举,并将常规值定义为2的幂,这是使用按位左移运算符<<最容易实现的。从C#7.0开始,您还可以使用像0b_0000_0000_0010_0000这样的二进制文字。然后可以将现有值组合以形成新的值。现在

[Flags] 
enum MyEnum 
{ 
    None = 0, 
    A = 1 << 0, 
    B = 1 << 1, 
    C = 1 << 2, 
    D = 1 << 3, 
    E = 1 << 4, 
    ... 
    X = 1 << 23, 
    Y = 1 << 24, 
    Z = 1 << 25, 
    Vowels = A | E | I | O | U 
} 

,你可以制定这样的

IEnumerable<MyEnum> query = Enum.GetValues(typeof(MyEnum)) 
    .Cast<MyEnum>() 
    .Where(x => (x & MyEnum.Vowels) == MyEnum.None); 
foreach (MyEnum item in query) { 
    ... 
} 

在第一解决方案的优点是查询,你可以用一个位与操作进行测试。

您最多可以定义32个幂。如果您需要更多,则可以将枚举的基本类型定义为long并使用最多64个标志值(加上现有标志值的组合)。

[Flags] 
enum MyEnum : long 
{ 
    ... 
} 
+0

这可能是最完整的答案。最简单的做法是指定各种你想跳过的枚举集合,这样你可以保存这些跳过集合,并且可以通过你想要的任何标准传入Except。 – SPFiredrake 2012-03-12 17:42:39

+0

是的,你也可以保留各种查询。 – 2012-03-12 17:46:03

+1

我添加了另一个解决方案,仅使用按位AND进行测试。它不需要任何数组或HashSets作为例外值。请参阅我的更新。 – 2012-03-12 22:56:51

1

我会做一个单独的一组元素组成的元音,然后使用LINQ两组之间的设置差异。

int[] vowels = {Letters.A, Letters.E, Letters.I, Letters.O, Letters.U}; 
IEnumerable<int> consonant = Enum.GetValues(typeof(Letters)).Except(vowels); 
foreach (int consonant in consonants) 
{ 
    // Do something with each consonant 
} 
1

我可能只是使用LINQ - 使用Enum.GetValues(或使用Unconstrained Melody - 一个类型安全的泛型枚举/委托库我写的),让所有的值,则表示该值保持/通过跳跃Where子句。

如果你只是跳过特定的值,那么HashSet或类似的东西可能是有用的(如果你只跳过一个值,那就不值得) - 如果你基于条件跳过,那么满需要谓词。

例如:

public static IEnumerable<T> AllBut(T skipped) where T : struct 
{ 
    IEqualityComparer<T> comparer = EqualityComparer<T>.Default; 
    return AllBut<T>(t => !comparer.Equals(skipped, t)); 
} 

public static IEnumerable<T> AllBut(Func<T, bool> skipPredicate) where T : struct 
{ 
    IEqualityComparer<T> comparer = EqualityComparer<T>.Default; 
    return Enum.GetValues(typeof(T)) 
       .Cast<T>() 
       .Where(t => skipPredicate(t)); 
}