Domanda

Dato un numero iniziale, immagina una sequenza infinita delle sue metà successive.

1, 0.5, 0.25, 0.125, ...

(Ignora qualsiasi instabilità numerica inerente a double.)

Questo può essere fatto in un'unica espressione senza scrivere metodi di estensione personalizzati o metodi del generatore?

È stato utile?

Soluzione

Non conosco un modo a espressione singola ma ho trovato questo codice di generatore intelligente qui: http://csharpindepth.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);
   }
}

Nel tuo caso lo useresti:

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

Altri suggerimenti

Per divertimento, ecco un trucco per creare una vera sequenza infinita in una singola espressione. Le prime due definizioni sono i campi di classe, in modo che non richiedano inizializzate un'espressione.

double? helper;
IEnumerable<double> infinite;

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

Ecco una risposta simile a quella fornita @hvd, ma usando il Y Operatore definito qui, questo rimuove la necessità delle variabili locali:

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 di esempio sarebbe:

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

Che produrrebbe 20, 10, 5, 2,5 ecc ...

Non consiglierei di usarlo nel codice di produzione ma è divertente.

Il Y L'operatore consente inoltre altre espressioni di lambda ricorsive, ad esempio:

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

In realtà non è infinito, ma come entrambi Repeat e Select Usa l'esecuzione differita, non perderai alcuna prestazione.

Non conosco alcun modo nativo per creare un'espressione infinita LINQ.

Oppure puoi scrivere manualmente la versione infinita di .Repeat

Non conosco alcun modo per creare una sequenza infinita con Linq dritto. Ma potresti fare un molto lungo sequenza.

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

Tuttavia, da quando double ha precisione finita, non otterrai altro che zero dopo n diventa troppo alto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top