Pregunta

Dado un número inicial, imagine una secuencia infinita de sus mitades sucesivas.

1, 0.5, 0.25, 0.125, ...

(Ignore cualquier inestabilidad numérica inherente a double.)

¿Se puede hacer esto en una sola expresión sin escribir ningún método de extensión personalizado o métodos de generador?

¿Fue útil?

Solución

No sé de una forma de expresión única, pero aquí encontré este inteligente código generador: http://csharpintepth.com/articles/chapter11/streaminganditerators.aspx

public static IEnumerable<TSource> Generate<TSource>(TSource start,
                                                  Func<TSource,TSource> step)
{
   TSource current = start;
   while (true)
   {
       yield return current;
       current = step(current);
   }
}

En su caso lo usaría:

foreach (double d in Generate<double>(1, c => c / 2))
{
    ...
}

Otros consejos

Por diversión, aquí hay un truco para crear una secuencia infinita real en una sola expresión. Las dos primeras definiciones son campos de clase, por lo que no requieren una expresión para ser inicializada.

double? helper;
IEnumerable<double> infinite;

infinite = new object[] { null }.SelectMany(dummy => new double[] { (helper = (helper / 2) ?? 1).Value }.Concat(infinite));

Aquí hay una respuesta similar a la que se proporcionó @HVD, pero usando el Y operador definido aquí, esto elimina la necesidad de las variables locales:

public static Func<A, R> Y<A, R>(Func<Func<A, R>, Func<A, R>> f)
{
    return t => f(Y(f))(t);
}

var halves = Y<double, IEnumerable<double>>(self => d => new[] { 0d }.SelectMany(_ => new[] { d }.Concat(self(d / 2))));

Un uso de ejemplo sería:

foreach (var half in halves(20))
    Console.WriteLine(half);

Que emitiría 20, 10, 5, 2.5 etc ...

No recomendaría usar esto en el código de producción, pero es divertido.

los Y El operador también permite otras expresiones de lambda recursivas, por ejemplo:

var fibonacci = Y<int, int>(self => n => n > 1 ? self(n - 1) + self(n - 2) : n);
var factorial = Y<int, int>(self => n => n > 1 ? n * self(n - 1) : n);
var hanoi = Y<int, int>(self => n => n == 1 ? 1 : 2 * self(n - 1) + 1);
Enumerable.Repeat(1, int.MaxValue).Select((x, i) => x / Math.Pow(2, i))

En realidad no es infinito, sino como ambos Repeat y Select Use la ejecución diferida, no perderá ningún rendimiento.

No conozca ninguna forma nativa de crear una expresión infinita de Linq.

O puede escribir manualmente la versión infinita de .Repeat

No sé de ninguna forma de hacer una secuencia infinita con Linq recto. Pero podrías hacer un muy largo secuencia.

var sequence = Enumerable.Range(0, int.MaxValue)
                         .Select(n => Math.Pow(2, -n));

Sin embargo, desde double tiene precisión finita, no obtendrás más que ceros después n se pone demasiado alto.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top