2012-03-12 14 views
11

La parte clave de mi pregunta es la omisión. Planeo usar un tipo de enumeración que tiene alrededor de 20 elementos. Quiero iterar a través de este conjunto, pero necesito omitir un elemento o dos cada vez. Qué omitir se conoce de antemano. Un ejemplo comparable es el tipo de enumeración que consta de todas las letras del alfabeto, y al iterar, quiero omitir todas las vocales.¿Cómo iterar a través del tipo de enumeración mientras se saltan algunos valores?

¿Cómo debo codificar la iteración de una manera elegante/eficiente? ¿Debo hacer un conjunto separado de elementos que consta de vocales? No tengo código para mostrar porque solo estoy pensando en el problema.

Respuesta

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

, es necesario especificar el fin de obtener la magia de LINQ. Except solo no lo hará.


ACTUALIZACIÓN:

tengo otra idea. Puede definir la enumeración con FlagsAttribute y definir los valores normales como potencias de 2, lo que se logra más fácilmente con el operador de desplazamiento a la izquierda <<. Comenzando con C# 7.0, también puede usar literales binarios como 0b_0000_0000_0010_0000. Entonces es posible combinar valores existentes para formar nuevos valores.

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

Ahora, se puede formular la consulta como esta

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

La ventaja sobre la primera solución es, que se puede realizar la prueba con un solo bit a bit AND-operación.

Puede definir hasta 32 potencias de dos. Si necesita más, puede definir el tipo base de la enumeración como long y usar hasta 64 valores de indicador (más combinaciones de valores de indicador existentes).

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

Esta es probablemente la respuesta más completa. Lo más fácil de hacer desde aquí es especificar varias colecciones de enumeraciones que le gustaría omitir, de esa manera puede tener esas colecciones salteadas guardadas y puede pasar el criterio que desee en Excepto. – SPFiredrake

+0

Sí, y también puede mantener varias consultas. –

+1

Agregué otra solución usando solo Y a nivel de bit para realizar la prueba. No requiere ninguna matriz o HashSets para los valores excepcionales. Por favor mira mi actualización –

1

Haría un conjunto separado de elementos que constaban de vocales, y luego tomaría la diferencia establecida entre los dos conjuntos utilizando 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

yo probablemente sólo tiene que utilizar LINQ - Enum.GetValues uso (o uso Unconstrained Melody - una biblioteca con seguridad de tipos genéricos de enumeración/delegado escribí) para obtener todos los valores, entonces expreso que valora a mantener/saltar a través de una Where cláusula.

Si solo está salteando valores específicos, un HashSet o algo similar puede ser útil (no vale la pena si solo se saltea uno, por supuesto) - si se salta basándose en una condición, entonces un completo -se requiere predicado-soplado.

Por ejemplo:

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