【问题标题】:Create Fibonacci series using lambda operator使用 lambda 运算符创建斐波那契数列
【发布时间】:2012-01-27 13:26:08
【问题描述】:

我正在尝试解决 Project Euler 中的一个问题,它正在创建一个直到 400 万的斐波那契数列,并添加该系列中的偶数,这显然是非常容易的任务,我会在 2 分钟内回答它,

int result=2;
int first=1;
int second=2;
int i=2;

while (i < 4000000)
{
    i = first + second;

    if (i % 2 == 0)
    {
       result += i;
    }

    first = second;
    second = i;
 }

 Console.WriteLine(result);

但我想使用 lambda 表达式来实现它

我的努力是这样的

DelType del = (oldVal, newVal) =>((oldVal==0?1:newVal  + newVal==1?2:oldVal+newVal) % 2 == 0) ? oldVal + newVal : 0;

int a=del(0, 1);

请建议如何完成此操作

【问题讨论】:

  • 我建议先尝试在 Linq 语句中执行此操作。这更具可读性,之后您可以轻松地将其转换为 lambda 语法。

标签: c# lambda


【解决方案1】:

一种有效的衬里:

Func<int, int, int, int, int> fib = null;
fib = (a, b, counter, n) => counter < n ? fib(b, a + b, counter+1, n) : a;
        //print the 9th fib num
        Console.WriteLine(fib(0,1,1,9)); 

输出:21

【讨论】:

    【解决方案2】:

    类似于 Func 两线,现在使用本地函数可以这样完成:

    int Fibonacci(int i) => i <= 1 ? i : Fibonacci(i - 1) + Fibonacci(i - 2);
    

    【讨论】:

      【解决方案3】:
      public static void fibSeriesEx3()
      {
          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();
          }
      }
      

      【讨论】:

        【解决方案4】:

        使用这个递归函数

        Func<int, int> fib = null;
        fib = (x) => x > 1 ? fib(x-1) + fib(x-2) : x;
        

        示例用法:

        Console.WriteLine(fib(10));
        

        【讨论】:

        • 我不确定它是否会编译。我的意思是,在分配之前让 lambda 引用自身...
        • @ivowiblo lambda 可以引用自身,只要在代码示例中的语句之前分配变量即可。示例:Func&lt;int, int&gt; fib = null; fib = x =&gt; x &gt; 1 ? fib(x - 1) + fib(x - 2) : x;
        • @phoog:请您帮我完成上述查询的完整解决方案,因为在运行上述 LINQ 查询后,我不知道如何在 OCnsole 窗口上查看相同内容或在控制台窗口上打印相同内容.
        • @sukumar 你到底有什么问题?你试过什么?也许你应该发布一个新问题。
        • @phoog: 我写了一个for 循环为for (int i = 0; i &lt; 10; i++) Console.WriteLine(fib(i)); 然后得到输出为0 1 1 2 3 5 8 13 21 34
        【解决方案5】:

        我知道这是一个老问题,但我今天也在处理同样的问题,并得出了这个运行时间为 O(n) 的简洁函数式解决方案:

        static int FibTotal(int limit, Func<int, bool> include, int last = 0, int current = 1)
        {
            if (current < limit)
                return FibTotal(limit, include, current, last + current) + 
                                       (include(current) ? current : 0);
            else
                return 0;
        }
        

        如果你首先定义这个便利类,你也可以获得一个不错的单行解决方案(也许这样的东西已经存在于 .NET 框架中,但我找不到它):

        public static class Sequence
        {
            public static IEnumerable<T> Generate<T>(T seed, Func<T, T> next)
            {
                while (true)
                {
                    yield return seed;
                    seed = next(seed);
                }
            }
        }
        

        那么解决方案就变成了:

        var result = Sequence.Generate(Tuple.Create(1, 1), 
                                       t => Tuple.Create(t.Item2, t.Item1 + t.Item2))
                             .Select(t => t.Item1)
                             .TakeWhile(i => i < 4000000)
                             .Where(i=> i % 2 == 0)
                             .Sum();
        

        【讨论】:

          【解决方案6】:

          你知道你可以做到:

          Func<int,int,int> func = (first, second) => {  
                                                    var result=2;
                                                    int i=2;
                                                    while (i < 4000000)
                                                    {
                                                        i = first + second;
                                                        if (i % 2 == 0)
                                                        {
                                                            result += i;
                                                        }
                                                        first = second;
                                                        second = i;
                                                    }
                                                    return result;
                                                  };
          

          【讨论】:

          • 感谢您的回复,但我想把它做成一个班轮,
          • 我只是好奇......为什么你需要在一行中使用它?我不知道这是否可能。
          • @ivowiblo:可悲的是,这也不会编译...(在指出其他人的相同错误之前修复您自己的代码;p)
          • 你可以利用这段时间来修复它而不是抱怨:)
          【解决方案7】:
          using System;
          using System.Collections;
          using System.Collections.Generic;
          using System.Linq;
          
          public class Fibonacci : IEnumerable<int>{
              delegate Tuple<int,int> update(Tuple<int,int> x);
              update func = ( x ) => Tuple.Create(x.Item2, x.Item1 + x.Item2);
          
              public IEnumerator<int> GetEnumerator(){
                  var x = Tuple.Create<int,int>(0,1);
                  while (true){
                      yield return x.Item1;
                      x = func(x);
                  }
              }
              IEnumerator IEnumerable.GetEnumerator() {
                  return GetEnumerator();
              }
          }
          
          class Sample {
              static public void Main(){
                  int result= (new Fibonacci()).TakeWhile(x => x < 4000000).Where(x => x % 2 == 0).Sum();
                  Console.WriteLine(result);//4613732
             }
          } 
          

          其他

          public static class Seq<T>{
              public delegate Tuple<T,T> update(Tuple<T,T> x);
          
              static public IEnumerable<T> unfold(update func, Tuple<T,T> initValue){
                  var value = initValue;
                  while (true){
                      yield return value.Item1;
                      value = func(value);
                  }
              }
          }
          
          class Sample {
              static public void Main(){
                  var fib = Seq<int>.unfold( x => Tuple.Create<int,int>(x.Item2, x.Item1 + x.Item2), Tuple.Create<int,int>(0,1));
                  int result= fib.TakeWhile(x => x < 4000000).Where(x => x % 2 == 0).Sum();
                  Console.WriteLine(result);
             }
          } 
          

          【讨论】:

          • 那个结果肯定是错的!如果fib(30) =&gt; 832040,那sum of fib(0) to fib(4000000) =&gt; 4613732不可能是真的
          • @leppie 确保你再次看到它? fib 系列在偶数时相加。 fib(x!=4000000), fib(?)
          • 查看我的答案以获得更简单的迭代器块来创建斐波那契数列。
          • @Jon Skeet 您的回答总是有帮助的。然而,这可能是个问题。这可能看起来很奇怪......
          【解决方案8】:

          我的第一个答案是完全误读了这个问题,但现在我重新阅读了它(感谢 MagnatLU!)我建议这个 非常适合 lambda 表达式。但是,它非常适合迭代器块和 LINQ 的组合:

          // Using long just to avoid having to change if we want a higher limit :)
          public static IEnumerable<long> Fibonacci()
          {
              long current = 0;
              long next = 1;
              while (true)
              {
                  yield return current;
                  long temp = next;
                  next = current + next;
                  current = temp;
              }
          }
          
          ...
          
          long evenSum = Fibonacci().TakeWhile(x => x < 4000000L)
                                    .Where(x => x % 2L == 0L)
                                    .Sum();
          

          【讨论】:

          • +1 for yield return,当您尝试在返回 IEnumerable&lt;T&gt; 的 lambda 中使用迭代器时,羞耻编译器返回 The yield statement cannot be used inside an anonymous method or lambda expression
          • @MegaMind:我正在寻找斐波那契数列的单行代码/语句。你能帮忙吗??
          • 我喜欢这个答案,但我认为 while 循环的第 2-4 行可以用next = current + (current = next); 简化为一行,有什么理由不这样做吗?
          • @JLRishe:是的——在我看来,这更令人困惑。它可能很有效,但是像这样的额外副作用让我很困惑。我宁愿有三个语句,每个语句都非常易于阅读。
          • 有道理。感谢您的答复。 :)
          【解决方案9】:

          如果您想要一个纯粹的递归 lambda 解决方案,请查看 this answer 以获得一些文章链接,其中显示了它是如何完成的。

          但是,超级的东西对我来说太疯狂了,所以我最好遵循另一个已经在这里的答案。

          【讨论】:

            【解决方案10】:

            这里是一个 lambda 表达式的 oneliner:

            Func<int, int, int, int, int> fib = null;
            fib = (n, a, b, res) => n == 0 ? res : fib(n - 1, b, a + b, n % 2 == 0 ? res : res + a + b);
            // usage: fib(n, 1, 0, 0)
            

            它在 x86 上使用 O(n) 堆栈空间和 O(n) 时间,在 x64 上使用 O(1) 堆栈空间(由于 x64 JIT 上的尾递归优化),因此它会在 32- 上在 n=400000 时失败位系统。

            编辑:它从最后而不是开始计算系列的偶数元素,但您应该知道如何使用 tailrec 将其作为 λ 来计算。

            【讨论】:

            • 我没有得到带有上述 linq 查询/表达式的斐波那契数列。得到滥用/奇怪的输出不是斐波那契。我试过fib(6,1,0,0)
            猜你喜欢
            • 2023-03-09
            • 1970-01-01
            • 2013-10-04
            • 2020-01-18
            • 2013-04-29
            • 1970-01-01
            • 2015-06-05
            相关资源
            最近更新 更多