2011-12-25 17 views
5

Sto cercando di risolvere una domanda in Project Euler, che sta creando una serie di fibonacci fino a 4 milioni e aggiungo i numeri pari che arrivano nella serie, questo è ovviamente un compito molto facile e rispondo in 2 minuti,Creare la serie di Fibonacci usando l'operatore lambda

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

ma voglio farlo utilizzando un'espressione lambda

il mio sforzo sta andando come

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

int a=del(0, 1); 

gentilmente suggerire come ottenere questo fatto

+0

Vorrei suggerire di provare prima a farlo in una dichiarazione di Linq. È un po 'più leggibile e dopo puoi facilmente convertirlo in sintassi lambda. –

risposta

15

La mia prima risposta è aver frainteso la questione del tutto, ma ora ho riletto (grazie MagnatLU!) Io suggerirei che questo non è una buona adatto per espressioni lambda. Tuttavia, è un brillante fit per una combinazione di blocchi iteratore e 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(); 
+0

heh! Ho letto male anche questo. – leppie

+1

+1 per 'yield return', restituisce il compilatore shame' L'istruzione yield non può essere utilizzata all'interno di un metodo anonimo o espressione lambda' quando si tenta di utilizzare iterator all'interno di lambda restituendo 'IEnumerable '. – MagnatLU

+0

@MegaMind: sto cercando un codice/istruzione a una riga per la serie Fibonacci. Puoi aiutare?? – venkat

0

Sai che puoi fare:

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

Grazie per la tua risposta, ma voglio renderlo un unico rivestimento, – MegaMind

+1

@Manvinder - questa è una riga ... –

+0

Sono solo curioso ... perché ne hai bisogno in una sola riga? Non so se è possibile. – ivowiblo

6

Usare questa funzione ricorsiva

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

Esempio di utilizzo:

Console.WriteLine(fib(10)); 
+1

Non sono sicuro se sarà compilato. Voglio dire, avendo il lambda referencing stesso prima che sia assegnato ... – ivowiblo

+1

@ivowiblo il lambda può fare riferimento a se stesso fino a quando la variabile viene assegnata prima dell'istruzione nell'esempio di codice. Esempio: 'Func fib = null; fib = x => x> 1? fib (x - 1) + fib (x - 2): x; ' – phoog

+0

Ha senso. Grazie. – ivowiblo

7

Ecco oneliner come espressione lambda:

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) 

Utilizza lo spazio di stack O (n) e il tempo O (n) su x86 e lo spazio di stack O (1) su x64 (a causa dell'ottimizzazione della ricorsione in coda su JIT x64), quindi fallirà per n = 400000 su 32- sistema bit.

Modifica: sta contando anche elementi di serie dalla fine, non l'inizio, ma si dovrebbe avere l'idea di come farlo con tailrec.

+0

Non sto ottenendo Fibonacci Series con la query/espressione linq sopra. Ottenere abuso/produzione strana non un fibonacci. Ho provato con 'fib (6,1,0,0)' – venkat

0

Nel caso in cui si desidera una soluzione lambda ricorsiva pura, dare un'occhiata a this answer per un paio di collegamenti ad articoli che mostrano come è fatto.

Tuttavia, quella roba da uber è troppo pazza per me, quindi farò meglio a seguire un'altra risposta che è già qui.

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

ALTRE

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

Questo risultato è sicuramente sbagliato! se 'fib (30) => 832040', non c'è modo che' sum of fib (0) to fib (4000000) => 4613732' possa essere vero – leppie

+1

@leppie Assicurati di vederlo di nuovo? la serie di fib aggiunge somma quando pari. fib (x! = 4000000), fib (?) <4000000 – BLUEPIXY

+0

Oops, ho letto COMPLETAMENTE la domanda! – leppie

0

So che questa è una vecchia questione, ma stavo lavorando sullo stesso problema di oggi e sono arrivato a questa soluzione concisa funzionale in stile con il tempo O (n) in esecuzione:

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

È inoltre possibile ottenere una bella soluzione di una sola riga, se prima si definisce questa classe convenienza (forse qualcosa di simile esiste già in.NET framework, ma non sono riuscito a trovarlo):

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

la soluzione diventa allora:

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

Simile al Func due-liner, ora con funzioni locali si può fare In questo modo:

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