6

I am trying to solve a question in Project Euler, which is creating a fibonacci series until 4 million, and add the even numbers that come in the series, this is obviously very easy task and I answer it in 2 mins,

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

but I want to do it using a lambda expression

My effort is going like

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

int a=del(0, 1);

Kindly suggest how to get this done

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Manvinder
  • 4,495
  • 16
  • 53
  • 100
  • I would suggest to first try doing it in a Linq statement. That's a little more readable and after that you can easily convert it to lambda syntax. – Wouter de Kort Dec 25 '11 at 07:44

10 Answers10

18

My first answer was having misread the question completely, but now I've reread it (thanks MagnatLU!) I'd suggest that this isn't a good fit for lambda expressions. However, it's a brilliant fit for a combination of iterator blocks and 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();
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    +1 for `yield return`, shame compiler returns `The yield statement cannot be used inside an anonymous method or lambda expression` when you try to use iterator inside lambda returning `IEnumerable`. – MagnatLU Dec 25 '11 at 10:52
  • @MegaMind: I'm looking for a one line code/statement for Fibonacci series. Can you help?? – venkat Feb 15 '13 at 04:56
  • I like this answer, but I think lines 2-4 of the while loop could be simplified into a single line with `next = current + (current = next);` Is there any reason not to do so? – JLRishe Jun 29 '13 at 05:55
  • 1
    @JLRishe: Yes - it's much more confusing, in my view. It may well work, but extra side effects like that confused the heck out of me. I'd much rather have three statements, each of which is really simple to read. – Jon Skeet Jun 29 '13 at 06:14
  • public static IEnumerable FibonacciSequence() { BigInteger a = 0, b = 1; while (true) { yield return a; a += b; yield return b; b += a; } } – Auto Jul 16 '20 at 00:04
8

Use this recursive function

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

Example Usage:

Console.WriteLine(fib(10));
Ravi Yenugu
  • 3,895
  • 5
  • 40
  • 58
Shraddha
  • 2,337
  • 1
  • 16
  • 14
  • 1
    I'm not sure if it will compile. I mean, having the lambda referencing itself before it's assigned... – Ivo Dec 25 '11 at 08:04
  • 1
    @ivowiblo the lambda can reference itself as long as the variable is assigned before the statement in the code example. Example: `Func fib = null; fib = x => x > 1 ? fib(x - 1) + fib(x - 2) : x;` – phoog Dec 27 '11 at 18:19
  • @phoog: Please Can you help me in complete solution for the above query since i'm not getting how to see the same on OCnsole window or printing the same on console window after running the above LINQ query. – venkat Feb 15 '13 at 04:54
  • @sukumar what exactly are you having trouble with? What have you tried? Perhaps you should post a new question. – phoog Feb 20 '13 at 20:34
  • @phoog: I written a `for` loop as `for (int i = 0; i < 10; i++) Console.WriteLine(fib(i));` Then got the output as `0 1 1 2 3 5 8 13 21 34` – venkat Apr 28 '13 at 12:28
7

Here's oneliner as a lambda expression:

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)

It uses O(n) stack space and O(n) time on x86 and O(1) stack space on x64 (due to tail recursion optimisation on x64 JIT), so it will fail for n=400000 on 32-bit system.

Edit: it is counting even elements of series from the end, not the beginning, but you should get the idea how to do it as λ with tailrec.

MagnatLU
  • 5,967
  • 1
  • 22
  • 17
  • I'm not getting Fibonacci Series with the above linq query/expression. Getting abuse/odd output not a fibonacci. I tried with `fib(6,1,0,0)` – venkat Apr 28 '13 at 12:24
3

Similar to the Func two-liner, now with local functions it can be done like this:

int Fibonacci(int i) => i <= 1 ? i : Fibonacci(i - 1) + Fibonacci(i - 2);
SET
  • 158
  • 1
  • 3
  • 9
1
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
   }
} 

OTHER

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);
   }
} 
BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70
  • That result is surely wrong! if `fib(30) => 832040`, there is no way `sum of fib(0) to fib(4000000) => 4613732` can be true – leppie Dec 25 '11 at 09:46
  • 1
    @leppie Make sure you see it again? fib series add sum when even. fib(x!=4000000), fib(?) < 4000000 – BLUEPIXY Dec 25 '11 at 09:51
  • 1
    See my answer for a somewhat simpler iterator block to create the Fibonacci sequence. – Jon Skeet Dec 25 '11 at 10:10
  • @Jon Skeet Your answer is always helpful. However, this may be it for question. It might seem strange... – BLUEPIXY Dec 25 '11 at 10:19
0

I know this is an old question, but I was working on the same problem today and arrived at this concise functional-style solution with O(n) running time:

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

You can also get a nice one-line solution if you first define this convenience class (maybe something like this already exists in the .NET framework, but I was unable to find it):

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

The solution then becomes:

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();
JLRishe
  • 99,490
  • 19
  • 131
  • 169
0
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();
    }
}
Juri Noga
  • 4,363
  • 7
  • 38
  • 51
Sivakishore Teru
  • 216
  • 1
  • 2
  • 9
0

One liner that works:

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

output: 21

0

You know you can do:

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;
                                        };
Ivo
  • 8,172
  • 5
  • 27
  • 42
0

Just in case you wanted a pure recursive lambda solution, take a look at this answer for a couple of links to articles showing how it's done.

However, that uber stuff is too mad for me, so I'd better follow another answer that is already here.

Community
  • 1
  • 1
Pavel Gatilov
  • 7,579
  • 1
  • 27
  • 42