2009-03-30 15 views
6

Attualmente sto facendo alcuni problemi di Project Euler e quelli precedenti spesso coinvolgono cose come numeri di Fibonacci o numeri primi. L'iterazione su di essi sembra essere una scelta naturale per LINQ, almeno per quanto riguarda la leggibilità e la percezione dell'eleganza del codice (sto cercando di utilizzare le caratteristiche specifiche della lingua, ove possibile e applicabile per avere un'idea delle lingue).LINQ query su liste potenzialmente infinite

Il mio problema è ora, se ho solo bisogno di un insieme di numeri fino ad un certo limite, come dovrei esprimerlo al meglio? Attualmente ho hard-coded il rispettivo limite nell'iteratore ma mi piacerebbe davvero che l'enumeratore restituisse l'elenco fino a quando qualcosa all'esterno non decide più di interrogarlo, poiché è oltre un certo limite. Quindi, in sostanza, ho un iteratore potenzialmente infinito, ma prendo solo un numero finito di numeri da esso. So che queste cose sono banali nei linguaggi funzionali, ma mi chiedo se anche C# lo consenta. L'unica altra idea che avrei avuto sarebbe quella di avere un iteratore Primes (lungo) che ritorna primi fino ad un certo limite, allo stesso modo per altre sequenze.

Qualche idea?

risposta

10

La maggior parte dei metodi LINQ (Classe enumerabile) sono pigri. Così, per esempio, non c'è niente di sbagliato con:

var squares = Enumerable.Range(0, Int32.MaxValue).Select(x=>x*x); 

È possibile utilizzare il metodo Prendere per limitare i risultati:

var 10squares = squares.Take(10); 

var smallSquares = squares.TakeWhile(x => x < 10000); 

Modifica: le cose che dovete evitare sono funzioni che restituiscono "pigramente "ma devi consumare l'intero enumerabile per produrre un risultato. Per esempio, il raggruppamento o l'ordinamento:

var oddsAndEvens = Enumerable.Range(0, Int32.MaxValue) 
          .GroupBy(x => x % 2 == 0); 
foreach (var item in oddsAndEvens) { 
    Console.WriteLine(item.Key); 
} 

(Che ti probabilmente vi darà un OutOfMemoryExeption a 32 bit.)

+0

Ah, ok, non sapevano TakeWhile finora. Ho solo pensato che usare Dove selezionare i numeri che vorrei non funzionasse in quanto LINQ non ha idea che i numeri siano in aumento, per esempio. Sembra carino, anzi :) – Joey

+0

+1, bel riassunto. Ho anche provato a elaborare un po 'su questo argomento: http://blog.casualdev.net/2009/10/linq-and-infinite-enumerations.html –