【问题标题】:more ruby way of doing project euler #2更多的红宝石方式做项目欧拉#2
【发布时间】:2010-06-12 16:49:13
【问题描述】:

我正在尝试学习 Ruby,并且正在解决一些 Project Euler 问题。我这样解决了problem number two

def fib(n)
  return n if n < 2
  vals = [0, 1]
  n.times do
    vals.push(vals[-1]+vals[-2])
  end
  return vals.last
end
i = 1
s = 0
while((v = fib(i)) < 4_000_000)
  s+=v if v%2==0
  i+=1
end
puts s

虽然这行得通,但它似乎不是很像 ruby​​ ——我无法像第一个 (puts (0..999).inject{ |sum, n| n%3==0||n%5==0 ? sum : sum+n }) 那样想出任何好的纯 Ruby 答案。

【问题讨论】:

    标签: ruby


    【解决方案1】:

    对于一个好的解决方案,为什么不创建一个斐波那契数生成器,例如 PrimeTriangular 示例 I gave here

    由此,您可以使用漂亮的Enumerable 方法来处理问题。您可能想知道偶数斐波那契数是否也有任何模式。

    编辑您的问题以发布您的解决方案...

    注意:有比枚举它们更有效的方法,但它们需要更多的数学运算,不会像这样清晰,并且只有在 400 万更高时才会发光。

    由于 demas 发布了解决方案,这里有一个清理后的版本:

    class Fibo
      class << self
        include Enumerable
    
        def each
          return to_enum unless block_given?
          a = 0; b = 1
          loop do
            a, b = b, a + b
            yield a
          end
        end
      end
    end
    
    puts Fibo.take_while { |i| i < 4000000 }.
              select(&:even?).
              inject(:+)
    

    【讨论】:

    • 如果您在编写这样的生成器时遇到困难,请查看以下内容:davidflanagan.com/2007/08/…
    • @Michael:天哪!那篇文章是对Fiber可怕 使用,而且太复杂了(更不用说慢了)。如果你需要类似的东西,写一个很好的枚举(看看我指的三角数生成器)并得到一个Enumerator并使用next,但即使这样也应该避免。
    • 我在下面发布我的版本。请检查一下。是你的意思吗?
    • @Marc-AndréLafortune 为什么将i 传递给1.upto(Float::INFINITY) do |i| 中的块?它看起来不像你在使用它......另外,你能解释一下 Float::INFINITY 是如何在这里工作的吗?对我来说,它的意思是“永远做某事”,但显然我错了。
    • @Mohamad 这是来自 dema 下面的回答,但你是对的,这可以进一步简化。我已经相应地编辑了我的答案。不,你是对的,它是一个无限循环,但是将它用作可枚举项可以很容易地只取其中的几个项目。
    【解决方案2】:

    我的版本基于 Marc-André Lafortune 的回答:

    class Some
      @a = 1
      @b = 2
    
      class << self
        include Enumerable
    
        def each
          1.upto(Float::INFINITY) do |i|
            @a, @b = @b, @a + @b
            yield @b
          end
        end
      end
    end
    
    puts Some.take_while { |i| i < 4000000 }.select { |n| n%2 ==0 }
              .inject(0) { |sum, item| sum + item } + 2
    

    【讨论】:

    • 是的,这是一个很好的方法。我用稍微改进的版本编辑了我的答案。
    • 请注意,您的版本的一个问题是您不能多次调用它...Some.first # =&gt; 3; Some.first =&gt; 5
    【解决方案3】:
    def fib
      first, second, sum = 1,2,0
      while second < 4000000
        sum += second if second.even?
        first, second = second, first + second
      end
      puts sum
    end
    

    【讨论】:

      【解决方案4】:

      您不需要return vals.last。你可以只做vals.last,因为默认情况下Ruby会返回最后一个表达式(我认为这是正确的术语)。

      【讨论】:

        【解决方案5】:
        fibs = [0,1]
        begin
          fibs.push(fibs[-1]+fibs[-2])
        end while not fibs[-1]+fibs[-2]>4000000
        puts fibs.inject{ |sum, n| n%2==0 ? sum+n : sum }
        

        【讨论】:

          【解决方案6】:

          这就是我得到的。我真的不认为有必要将它包装在一个类中。你当然可以在一个更大的程序中,但在一个小脚本中,我发现它只是为解释器创建额外的指令。你可以选择偶数,而不是拒绝奇数,但它几乎是一样的。

          fib = Enumerator.new do |y|
            a = b = 1
            loop do
              y << a
              a, b = b, a + b
            end
          end
          
          puts fib.take_while{|i| i < 4000000}
                  .reject{|x| x.odd?}
                  .inject(:+)
          

          【讨论】:

            【解决方案7】:

            这就是我的方法。我知道它可以减少代码行数,但也许你可以从中获取一些东西。

            class Fib
              def first
                @p0 = 0
                @p1 = 1
                1
              end
              def next
                r = 
                  if @p1 == 1
                    2
                  else
                    @p0 + @p1
                  end
                @p0 = @p1
                @p1 = r
                r
              end
            end
            
            c = Fib.new
            f = c.first
            r = 0
            while (f=c.next) < 4_000_000
              r += f if f%2==0
            end
            puts r
            

            【讨论】:

            • 如果你以@p0 = 1 开头,你可以摆脱你的if... 另外,Ruby 有并行赋值,这在这里很有用。你知道2.even? 返回true吗?
            • 我知道。我刚刚从我的 Project Euler 任务存档中发布了我的存档代码。这是我很久以前写的。
            【解决方案8】:

            我是 Ruby 新手,但这是我想出的答案。

             x=1
             y=2
             array = [1,2]
             dar = [] 
               begin
                 z = x + y
            
                   if z % 2 == 0
                     a = z
                     dar << a
                   end
                 x = y
                 y = z
                 array << z
               end while z < 4000000
                 dar.inject {:+}
                 puts "#{dar.sum}"
            

            【讨论】:

              【解决方案9】:
              def fib_nums(num)
                  array = [1, 2]
                  sum = 0
                  until array[-2] > num
                      array.push(array[-1] + array[-2])
                  end
                  array.each{|x| sum += x if x.even?}
                  sum
              end
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2015-09-28
                • 2013-03-19
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-07-20
                • 2013-02-23
                • 2013-05-22
                相关资源
                最近更新 更多