2009-05-05 34 views
5

Después de responder this question que arme el siguiente código C# sólo por diversión:Infinito IEnumerable en un bucle foreach

public static IEnumerable<int> FibonacciTo(int max) 
{  
    int m1 = 0; 
    int m2 = 1; 
    int r = 1; 

    while (r <= max) 
    { 
     yield return r; 

     r = m1 + m2; 
     m1 = m2; 
     m2 = r; 
    } 
} 

foreach (int i in FibonacciTo(56).Where(n => n >= 24)) 
{ 
    Console.WriteLine(i); 
} 

El problema es que no me gusta necesitar pasar un parámetro max a la función. En este momento, si no uso uno, el código mostrará los datos correctos, pero luego se bloqueará a medida que IEnumerable continúe funcionando. ¿Cómo puedo escribir esto para que tan sólo pudiera utilizar de esta manera:

foreach (int i in Fibonacci().Where(n => n >= 24 && n <= 56)) 
{ 
    Console.WriteLine(i); 
} 

Respuesta

12

En su lugar, necesita utilizar una combinación de SkipWhile y TakeWhile.

foreach (int i in Fibonacci().SkipWhile(n => n < 24) 
          .TakeWhile(n => n <= 56)) 
{ 
    Console.WriteLine(i); 
} 

Estos son capaces de terminar bucles dependiendo de una condición; Where transmite su entrada (filtrando apropiadamente) hasta que la entrada se agote (en su caso, nunca).

+0

Me acababa de dar cuenta de esto y estaba a punto de publicarlo yo mismo. Extraño cómo finalmente escribir la pregunta a veces te apunta al obvio –

+0

Hmm ... mi problema básico es que estaba obsesionado con hacer esto en una sola expresión lambda. Ahora estoy tentado de escribir también una nueva extensión "SkipThenTakeWhile()" de IEnumerable que permitiría eso, si solo puedo pensar en un mejor nombre para ella;) –

+0

Aunque también me gusta escribir operadores LINQ, me pregunto si esto realmente surge con la frecuencia suficiente para merecer uno;) –

-2

no creo que esto es posible a menos que usted escribe su propio proveedor de LINQ. En el ejemplo que le diste, está utilizando LINQ to Objects que necesitará evaluar completamente el IEnumerable antes de que pueda aplicarle un filtro.

+4

Afortunadamente IEnumerable realmente no funciona así: aplica el filtro a medida que lo evalúa para que los datos se transmitan en lugar de repetirse. –

+0

Joel tiene razón, olvidé mis principios básicos de programación funcional donde una operación no puede tener un efecto secundario. –