2009-03-30 8 views
6

Je suis en train de faire quelques problèmes de Project Euler et les premiers impliquent souvent des choses comme des nombres de Fibonacci ou des nombres premiers. Iterating sur eux semble être un ajustement naturel pour LINQ, au moins dans la lisibilité et l'élégance perçue du code (j'essaie d'utiliser des fonctionnalités spécifiques au langage lorsque cela est possible et applicable pour avoir une idée des langues).Requêtes LINQ sur des listes éventuellement infinies

Mon problème est maintenant, si j'ai seulement besoin d'un ensemble de nombres jusqu'à une certaine limite, comment est-ce que je devrais le mieux exprimer ceci? Actuellement j'ai codé en dur la limite respective dans l'itérateur mais j'aimerais vraiment que l'énumérateur retourne la liste jusqu'à ce que quelque chose à l'extérieur décide de ne plus l'interroger, puisqu'il dépasse une certaine limite. Donc, fondamentalement, j'ai un itérateur potentiellement infini mais je n'en prends qu'un ensemble fini de nombres. Je sais que de telles choses sont triviales dans les langages fonctionnels, mais je me demande si C# permet cela aussi. La seule autre idée que j'avais serait d'avoir un itérateur Primes (long) qui renvoie les nombres premiers jusqu'à une certaine limite, de même pour les autres séquences.

Des idées?

Répondre

10

La plupart des méthodes LINQ (classe Enumerable) sont paresseuses. Ainsi, par exemple, il n'y a rien de mal avec:

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

Vous pouvez utiliser la méthode de prendre pour limiter les résultats:

var 10squares = squares.Take(10); 

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

Edit: Les choses que vous devez éviter sont des fonctions qui retournent « paresseusement mais il faut consommer tout l'énumérable pour produire un résultat. Par exemple, le groupement ou le tri:

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

(Cela vous donnera probablement un OutOfMemoryExeption sur 32 bits.)

+0

Ah, ok, ne savait pas TakeWhile jusqu'à présent. Je pensais juste qu'utiliser Où sélectionner les nombres que je veux ne fonctionnerait pas car LINQ n'a aucune idée que les nombres augmentent, par exemple. Cela semble bien, en effet :) – Joey

+0

+1, joli résumé. J'ai aussi essayé d'élaborer un peu sur ce sujet: http://blog.casualdev.net/2009/10/linq-and-infinite-enumerations.html –