Фибоначчи с одним вкладышем - PullRequest
21 голосов
/ 21 июня 2011

Я пытаюсь решить вопросы из Project Euler в Ruby one-liners, и мне любопытно, есть ли более элегантное решение для вопроса два :

Каждый новый член в последовательности Фибоначчи генерируется путем добавления двух предыдущих членов.Начиная с 1 и 2, первые 10 терминов будут:

1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

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

Вот мое однострочное решение в Ruby:

(1..32).inject([0,1]) {|arr, i| (arr << arr[-1] + arr[-2] if arr[-1] + arr[-2] <= 4000000) || arr}.inject(0) {|total, i| total += i.even? ? i : 0}

Моя главная проблема в том, что я использую диапазон (1..32) только потому, что случайно узнал, что это все, что нужно, пока числа в последовательности Фибоначчи не начнут превышать 4 000 000.Я бы предпочел, чтобы это было как-то встроено в одну строку, но я так и не смог разобраться.

Запятые не допускаются!

Ответы [ 17 ]

1 голос
/ 11 ноября 2015

Как обобщающее решение для ответов выше, с моими скромными дополнениями:

32.
  times.
  lazy.
  with_object([0, 1]).map { |_, fib| fib[1] = fib[0] + fib[0] = fib[1]; fib[0] }.
  take_while(&:>.to_proc.curry(2)[4*10**6]).
  select(&:even?).
  inject(:+)

Мне не очень нравится, как выглядит карри, но я не хотел, чтобы это выглядело как другие ответы. Альтернатива take_while на всякий случай:

  take_while { |value| value < 4*10**6 }.
1 голос
/ 01 марта 2013

С новым ленивым в ruby ​​2.0 вы можете написать вот так.

puts (1..Float::INFINITY).lazy.map{|n| (0..n).inject([1,0]) {|(a,b), _| [b, a+b]}[0] }.take_while{|n| n < 4000000}.select{|x| x % 2 == 0}.reduce(:+)
0 голосов
/ 22 декабря 2018

Сейчас я могу придумать 4 способа достижения цели Фибоначчи!

  1. Использование стабильной лямбды:
puts 'Fibonacci Sequence in a Line: ', ->(a=1, b=0) { 10.times.collect { (a, b = b, a + b)[0] } }.call

Это оценивает 10 серий. Но если вы хотите получить номер пользователя:

puts 'Fibonacci Sequence in a Line: ', ->(a=1, b=0) { gets.to_i.times.collect { (a, b = b, a + b)[0] } }.call
  1. Используя метод tap:
[0, 1].tap { |a| 10.times { a.push(a[-1] + a[-2]) } }
  1. Использование метода reduce / inject:
(1..10).reduce([0, 1]) { |a| a.push(a.last(2).sum) }

или

10.times.reduce([0, 1]) { |a| a.push(a.last(2).sum) }
  1. Используя метод each_with_object или map.with_object:
10.times.each_with_object([0, 1]) { |_, a| a.push(a.last(2).sum) }

Примечание. Если у вас нет Ruby 2.4+, у вас может не быть метода sum. В этом случае вы можете добавить два последних элемента с помощью ary[-2] + ary[-1] или ary.last(2).reduce(:+).

Подходя к вашей проблеме:

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

[0, 1].tap { |a| until (s = a.last(2).sum) > 4_000_000 do a.push(s) end }.select(&:even?).sum

Или (что не так здорово):

[0, 1].tap { |a| loop while a.push(a.last(2).sum)[-1] < 4_000_000 }.tap(&:pop).select(&:even?).sum

Выходы: 4613732

Надеюсь, это поможет!

0 голосов
/ 10 сентября 2018

Простой и элегантный - лучший способ, верно?

a0 = 1; a1 = 1; 20.times {|i| b = a0 + a1; a0 = a1; a1 = b; puts b };

Выход:

2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
17711
=> 20
0 голосов
/ 03 августа 2017

Вот мой единственный вкладыш, с таблицей @fib, заполняемой, когда мы получаем, что метод возвращает ..

@fib=[0,1];def fib num; return 0 if num < 0; @fib[num]||=fib(num-1)+fib(num-2);end
0 голосов
/ 20 февраля 2016

(1..32).inject([0, 1]) { |fib| fib << fib.last(2).inject(:+) }

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

Вот решение для одной строки в рубине Euler prob # 2

(0..4000000).take_while{|i| (0..i).reduce([1,0]){|(a,b), _| [b, a+b]}[0] <= 4000000 }.map{|i| (0..i).reduce([1,0]){|(a,b), _| [b, a+b]}[0] }.select{|i| i%2 == 0}.reduce(:+)

или для лучшей читабельности ??

(0..4000000) .
take_while {|i| (0..i).reduce([1,0]){|(a,b), _| [b, a+b]}[0] <= 4000000} .
map {|i| (0..i).reduce([1,0]){|(a,b), _| [b, a+b]}[0]} .
select {|i| i%2 == 0} .
reduce(:+)
...