2012-03-12 8 views
11

Kluczową częścią mojego pytania jest pomijanie. Planuję użyć typu wyliczeniowego, który ma około 20 elementów. Chcę iterować przez ten zestaw, ale za każdym razem trzeba pominąć element lub dwa. To, co pominąć, jest znane z góry. Porównywalny przykład to typ wyliczeniowy, który składa się ze wszystkich liter alfabetu, a podczas iteracji chcę pominąć wszystkie samogłoski.Jak iterować przez typ wyliczeniowy, pomijając niektóre wartości?

Jak powinienem kodować iterację w elegancki/wydajny sposób? Czy powinienem zrobić osobny zestaw elementów składających się z samogłosek? Nie mam kodu do pokazania, ponieważ właśnie myślę o problemie.

Odpowiedz

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

Musisz rzucać w celu uzyskania magii LINQ. Except sam nie zrobi tego.


UPDATE:

mam inny pomysł. Możesz zdefiniować enum z FlagsAttribute i zdefiniować regularne wartości jako moce 2, co jest najłatwiejsze z operatorem przesunięcia bitowego w lewo o <<. Począwszy od wersji C# 7.0, można również używać literałów binarnych, takich jak 0b_0000_0000_0010_0000. Następnie możliwe jest połączenie istniejących wartości w celu utworzenia nowych wartości.

[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 
} 

Teraz można sformułować zapytanie jak ten

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

przewagę nad pierwszym rozwiązaniem jest, że można wykonać test z jednym bitowe AND operacji.

Możesz zdefiniować do 32 potęg dwóch. Jeśli potrzebujesz więcej, możesz zdefiniować podstawowy typ wyliczenia jako long i użyć maksymalnie 64 wartości flag (plus kombinacji istniejących wartości flag).

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

Jest to prawdopodobnie najbardziej kompletna odpowiedź. Najłatwiejszą rzeczą do zrobienia jest określenie różnych kolekcji Enums, które chcesz pominąć, w ten sposób możesz zapisać te kolekcje pominięć i spełnić dowolne kryteria w Except. – SPFiredrake

+0

Tak, można również zachować różne zapytania. –

+1

Dodałem kolejne rozwiązanie, używając tylko bitowego AND, aby wykonać test. Nie wymaga żadnych tablic ani HashSets dla wyjątkowych wartości. Zobacz moją aktualizację. –

1

Wykonywałbym oddzielny zestaw elementów składający się z samogłosek, a następnie przyjmowałam ustawioną różnicę między dwoma zestawami za pomocą 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

I pewnie właśnie używać LINQ - użyj Enum.GetValues (lub użyć Unconstrained Melody - rodzaj bezpieczny rodzajowe enum/delegata bibliotekę napisałem), aby uzyskać wszystkie wartości, które następnie wyrazić wartości, aby utrzymać/skip za pośrednictwem Where zdanie.

Jeśli pomijasz tylko określone wartości, może być użyteczny HashSet lub coś podobnego (nie wart tego, jeśli oczywiście pomijasz tylko jeden) - jeśli przeskakujesz w oparciu o warunek, to pełne - wymagany jest określony predykat.

Na przykład:

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)); 
}