2010-01-14 10 views
4

Comment écrire une expression LINQ (syntaxe d'appel de méthode préférée) qui donne une liste de nombres de fibonacci compris dans une certaine plage, disons 1 à 1000?Aide pour l'expression LINQ

Répondre

14

OK; pour une plus « FP » Réponse:

using System; 
using System.Collections.Generic; 
using System.Linq; 
static class Program 
{ 
    static void Main() 
    { 
     Func<long, long, long, IEnumerable<long>> fib = null; 
     fib = (n, m, cap) => n + m > cap ? Enumerable.Empty<long>() 
      : Enumerable.Repeat(n + m, 1).Concat(fib(m, n + m, cap)); 

     var list = fib(0, 1, 1000).ToList(); 
    } 
} 

Notez que en théorie cela peut être écrit comme une seule lambda, mais qui est very hard.

+0

Exactement ce dont j'avais besoin. Merci. :) – missingfaktor

+0

putain, que quelque impressionnant LINQ. +1 –

+5

Impressionnant LINQ? Cela ressemble plus à la programmation fonctionnelle 101 pour moi. Pourtant, pour les programmeurs C# les plus impératifs, il est forcément très impressionnant. – peSHIr

3

En utilisant la réponse iterator bloc de here:

foreach (long i in Fibonacci() 
      .SkipWhile(i => i < 1) 
      .TakeWhile(i => i <= 1000)) { 
     Console.WriteLine(i); 
    } 

ou pour une liste:

var list = Fibonacci().SkipWhile(i => i < 1).TakeWhile(i => i <= 1000) 
       .ToList(); 

Sortie:

1 
1 
2 
3 
5 
8 
13 
21 
34 
55 
89 
144 
233 
377 
610 
987 
+0

Je veux une solution qui n'utilise aucune boucle. Seules les méthodes LINQ sont autorisées. – missingfaktor

+1

Et que pensez-vous que la plupart des LINQ (-to-objects) sont sous le capot? Plus sérieusement; Qu'avez-vous exactement en tête? Si vous voulez dire à l'appelant, ajoutez simplement '.ToArray()' ou '.ToList()'. Si vous voulez dire dans la mise en œuvre, bien - c'est une séquence infinie ... vous devrez peut-être boucler à un moment donné ... –

+0

Je joue avec la programmation fonctionnelle et je ne veux donc pas de boucles explicites. C'est tout. – missingfaktor

2

Voici la solution de base de l'énumérateur. C'est une évaluation paresseuse. Le prochain numéro est généré lorsque MoveNext() est terminé.

foreach (int k in Fibonacci.Create(10)) 
     Console.WriteLine(k); 


    class Fibonacci : IEnumerable<int> 
    { 
     private FibonacciEnumertor fibEnum; 
     public Fibonacci(int max) { 
      fibEnum = new FibonacciEnumertor(max); 
     } 
     public IEnumerator<int> GetEnumerator() { 
      return fibEnum; 
     } 


     System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { 
      return GetEnumerator(); 
     } 
     public static IEnumerable<int> Create(int max) { 
      return new Fibonacci(max); 
     } 

     private class FibonacciEnumertor : IEnumerator<int> 
     { 
      private int a, b, c, max; 
      public FibonacciEnumertor(int max) { 
       this.max = max; 
       Reset(); 
      } 
      // 1 1 2 3 5 8 
      public int Current { 
       get { 

        return c; 
       } 
      } 
      public void Dispose() { 

      } 

      object System.Collections.IEnumerator.Current { 
       get { return this.Current; } 
      } 

      public bool MoveNext() { 

       c = a + b; 
       if (c == 0) 
        c = 1; 
       a = b; 
       b = c; 
       ; 
       return max-- > 0; 
      } 

      public void Reset() { 
       a = 0; 
       b = 0; 
      } 
     } 
    } 
+1

Ce qui est amusant, c'est que lorsque le compilateur a fini de le corriger, ce n'est pas très différent de l'approche de l'itérateur. écrivez ;-p –

+1

Vous avez raison, ce sera similaire à l'itératif. En fait ce que je voulais, c'est donner le même comportement que suivre. Enumerable.Range (1, 100); Le code est peut-être volumineux, mais il est réutilisable et n'entraîne aucune baisse de performance. – affan

2

pas très performant:

val fibonacci = Enumerable 
        .Range(0, 1000) 
        .Aggregate(new List<int>{1,0}, (b,j)=>{ 
           b.Insert(0,b[0]+b[1]); 
           return b; }); 
1

fin, mais une version rapide avec le mot-clé "rendement" :-)

IEnumerable<int> Fibonacci(int limit) 
{ 
int number = 1, old = 0; 
while (number < limit) 
{ 
    yield return number; 
    int tmp = number; number += old; old = tmp; 
} 
} 

var list = Fibonacci(1000).ToList(); 
0

plus facile pour imprimer fibonacci LINQ

 List<int> lst = new List<int> { 0, 1 }; 

     for (int i = 0; i <= 10; i++) 
     { 
      int num = lst.Skip(i).Sum(); 
      lst.Add(num); 

      foreach (int number in lst) 
       Console.Write(number + " "); 
      Console.WriteLine(); 
     }