【问题标题】:Help with LINQ Expression帮助 LINQ 表达式
【发布时间】:2011-01-04 23:22:42
【问题描述】:

如何编写一个 LINQ 表达式(首选方法调用语法),它给出一个位于特定范围内的斐波那契数列表,比如 1 到 1000?

【问题讨论】:

    标签: c# linq fibonacci


    【解决方案1】:

    使用 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();
            }
    

    【讨论】:

      【解决方案2】:

      较晚,但带有“yield”关键字的快速版本:-)

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

      【讨论】:

        【解决方案3】:

        性能不是很好:

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

        【讨论】:

          【解决方案4】:

          这里是枚举器基础解决方案。这是一个懒惰的评价。所以当 MoveNext() 完成时会生成下一个数字。

             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;
                      }
                  }
              }
          

          【讨论】:

          • 有趣的是,当编译器完成对它的修改时,这与迭代器块方法并没有太大不同——只是更难编写;-p
          • 是的,你说得对,它类似于迭代的。实际上我想要的是给出与以下相同的行为。 Enumerable.Range(1, 100);所以代码可能很大,但它是可重用的,并且不会影响性能。
          【解决方案5】:

          好的;更多“FP”答案:

          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();
              }
          }
          

          请注意,理论上这可以写成单个 lambda,但也就是 very hard

          【讨论】:

          • 正是我需要的。谢谢。 :)
          • 该死的,一些令人印象深刻的 LINQ。 +1
          • 令人印象深刻的 LINQ?在我看来,这更像是函数式编程 101。尽管如此,对于大多数命令式 C# 程序员来说,它一定会让人印象深刻。
          • 很高兴 C# 程序员被介绍到使用 LINQ 进行函数式编程,即使有些人还没有意识到这一点。当他们的思想准备好时,函数式程序员可以接管世界! [在这里插入邪恶的咯咯声]
          • Marc,我发现递归 lambda 的这个更清晰的解释,它实际上解决了斐波那契数,这比你提供的链接更清晰:blogs.msdn.com/b/wesdyer/archive/2007/02/02/…
          【解决方案6】:

          使用来自here 的迭代器块答案:

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

          或列表:

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

          输出:

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

          【讨论】:

          • 我想要一个不使用任何循环的解决方案。只允许使用 LINQ 方法。
          • 您认为 LINQ(-to-objects) 的大部分内容是什么?更严重;你到底有什么想法?如果您指的是来电者,只需添加.ToArray().ToList()。如果您的意思是在实现中,那么-它是一个无限序列...您可能必须在某个时候循环...
          • 我正在玩函数式编程,因此不需要显式循环。就是这样。
          猜你喜欢
          • 2011-05-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-06-10
          相关资源
          最近更新 更多