Создать ряд Фибоначчи с помощью лямбда-оператора - PullRequest
5 голосов
/ 25 декабря 2011

Я пытаюсь решить вопрос в Project Euler, который создает ряд Фибоначчи до 4 миллионов, и добавляет четные числа, которые входят в ряд, это, очевидно, очень простая задача, и я отвечаю на нее через 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);

но я хочу сделать это, используя лямбда-выражение

Мои усилия идут как

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

int a=del(0, 1);

Пожалуйста, подскажите, как это сделать

Ответы [ 10 ]

16 голосов
/ 25 декабря 2011

Моим первым ответом было неправильное прочтение вопроса, но теперь я перечитал его (спасибо MagnatLU!). Я бы предположил, что этот не хорошо подходит для лямбда-выражений.Тем не менее, это блестящий подходит для комбинации блоков итераторов и 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();
7 голосов
/ 25 декабря 2011

Вот онелинер как лямбда-выражение:

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)

Он использует пространство стека O (n) и время O (n) в x86, и пространство стека O (1) в x64 (из-за оптимизации хвостовой рекурсии в JIT x64), поэтому он потерпит неудачу при n = 400000 на 32- битовая система.

Редактировать: он считает даже элементы серии с конца, а не с начала, но вы должны понять, как сделать это как λ с tailrec.

7 голосов
/ 25 декабря 2011

Используйте эту рекурсивную функцию

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

Пример использования:

Console.WriteLine(fib(10));
1 голос
/ 25 января 2018

Как и в случае с двумя строками Func, теперь с локальными функциями это можно сделать так:

int Fibonacci(int i) => i <= 1 ? i : Fibonacci(i - 1) + Fibonacci(i - 2);
1 голос
/ 25 декабря 2011
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);
   }
} 
0 голосов
/ 22 марта 2019

Один лайнер, который работает:

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

0 голосов
/ 29 ноября 2016
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();
    }
}
0 голосов
/ 29 июня 2013

Я знаю, что это старый вопрос, но я работал над той же проблемой сегодня и пришел к этому краткому функциональному решению со временем выполнения 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 Framework, но я не смог его найти):

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();
0 голосов
/ 25 декабря 2011

На всякий случай, если вы хотите получить чисто рекурсивное лямбда-решение, посмотрите на этот ответ , чтобы получить пару ссылок на статьи, показывающие, как это делается.

Однако этот убер-материалслишком сумасшедший для меня, так что я лучше последую другому ответу, который уже здесь.

0 голосов
/ 25 декабря 2011

Вы знаете, что можете сделать:

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;
                                        };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...