Fibonacci One-Liner

cle*_*lem 22 ruby fibonacci

我正试图用Ruby单行解决Project Euler中的问题,我很好奇是否有更优雅的问题解决方案:

Fibonacci序列中的每个新术语都是通过添加前两个术语生成的.从1和2开始,前10个术语将是:

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

通过考虑Fibonacci序列中的值不超过四百万的项,找到偶数项的总和.

这是我在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}
Run Code Online (Sandbox Code Playgroud)

我主要担心的是我只使用范围(1..32),因为我碰巧知道在Fibonacci序列中的数字开始超过4,000,000之前,这一切都是必要的.我希望不知怎的,它会以某种方式构建在单行中,但我无法弄明白.

不允许使用半冒号!

Ale*_*ner 75

我最喜欢的解决方案是使用哈希值,其值可以通过匿名函数确定:

fibonacci = Hash.new{ |h,k| h[k] = k < 2 ? k : h[k-1] + h[k-2] }

fibonacci[6]  # => 8 
fibonacci[50] # => 12586269025
Run Code Online (Sandbox Code Playgroud)

这是一个"真正的"单行和Ruby-ish.

  • 非常聪明!但你使用冒号 - 不是使用分号的两倍吗? (4认同)
  • 好样的!通过使用哈希来驱动函数,您可以获得自动记忆.这很优雅! (4认同)
  • `fibonacci [2299]#=>堆栈级别太深(SystemStackError)` (2认同)
  • 我想强调两种方法之间的性能差异.哈希:`code`fibonacci = Hash.new {| h,k | h [k] = k <2?k:h [k-1] + h [k-2]}置于斐波那契[30] 832040 [完成0.1s]`code` Lambda:`code` fibo = lambda {| x | (x <2)?x:fibo.call(x-1)+ fibo.call(x-2)} 832040 [在1.7s完成]`代码` (2认同)
  • 没有冒号:`fib = Hash.new {| fib,n | fib [n] = fib [n - 1] + fib [n - 2]} .merge!(0 => 0,1 => 1) (2认同)

Way*_*rad 19

使用Ruby 1.9枚举器:

fib = Enumerator.new do |yielder|
  i = 0
  j = 1
  loop do
    i, j = j, i + j
    yielder.yield i
  end
end

p fib.take_while { |n| n <= 4E6 }
# => [1, 1, 2 ... 1346269, 2178309, 3524578]
Run Code Online (Sandbox Code Playgroud)

作为一行:

p Enumerator.new { |yielder| i, j = 0, 1; loop {i, j = j, i + j; yielder.yield i} }.take_while { |n| n <= 4E6}
Run Code Online (Sandbox Code Playgroud)


Son*_*tos 10

灵感来自亚历克斯的答案:

# Ruby 1.8.7
f = lambda { |x| x < 2 ? x : f.call(x-1) + f.call(x-2) }
puts f.call(6)   #=> 8

# Ruby 1.9.2
f = ->(x){ x < 2 ? x : f[x-1] + f[x-2] }
puts f[6]        #=> 8
Run Code Online (Sandbox Code Playgroud)

  • `fib = - >(n,i = 0,j = 1){(1..n).map {i = j + j = i}}`用`fib [7]调用它 (4认同)
  • `i = j + j = i`从左到右进行评估.起点`i = 0; j = 1`.首先`i`将被设置为1 + 0,因为=先于+.现在`i = 1; j = 0`.`i`将被设置为0 + 1.我们到达`i = 1; j = 1`.`i`将设置为1 + 1.`i = 2; j = 1`.`i`将被设置为1 + 2.`i = 3; j = 2`.`i`将被设置为2 + 3.`i = 5; j = 3`等等,从而产生Fibonacci序列. (2认同)

小智 7

我最喜欢的是:

def fib(n)
  (0..n).inject([1,0]) { |(a,b), _| [b, a+b] }[0]
end
Run Code Online (Sandbox Code Playgroud)

来自https://gist.github.com/1007228


Gar*_*ees 6

这个怎么样?

(((1 + 5 ** 0.5) / 2) ** 35 / 5 ** 0.5 - 0.5).to_i / 2
Run Code Online (Sandbox Code Playgroud)

(请参阅此答案以获得解释.)


lui*_*eis 5

这是一个ruby 2.0解决方案,不使用非懒惰的inject/reduce:

(1..Float::INFINITY).
  lazy.
  with_object([0,1]).
  map { |x, last| last[1] = last[0] + (last[0] = last[1]) }.
  select { |x| x % 2 == 0 }.
  take_while { |x| x < 4_000_000 }.
  reduce(&:+)
Run Code Online (Sandbox Code Playgroud)

我并不特别喜欢斐波那契发生器,因为它不包括初始值0.该解决方案还利用了第一个奇数是F 3(此序列发生器中的F 1).

更清洁(斐波那契)和正确(在Liber Abaci的定义中)解决方案将是:

(1..Float::INFINITY).
  lazy.
  with_object([0,1]).
  map { |x, last| last[1] = last[0] + (last[0] = last[1]);last[0] }.
  select { |x| x % 2 == 0 }.
  take_while { |x| x < 4_000_000 }.
  reduce(&:+)
Run Code Online (Sandbox Code Playgroud)

这个解决方案包括一个分号,但我不知道这样使用时它是否重要:).

[更新]

这是一个合适的Fibonacci生成器(从0开始)解决方案,没有分号(顺便说一句,这是一个javascript半结肠战争的东西?!?):)

(1..Float::INFINITY).
  lazy.
  with_object([0,1]).
  map { |x, last| last[0].tap { last[1] = last[0] + (last[0] = last[1]) } }.
  select { |x| x % 2 == 0 }.
  take_while { |x| x < 4_000_000 }.
  reduce(&:+)
Run Code Online (Sandbox Code Playgroud)