【问题标题】:ruby inject with conditional in block?红宝石注入有条件的块?
【发布时间】:2012-05-30 04:14:24
【问题描述】:

做第一个 Project Euler 问题:将 1 到 1000 之间的 3 和 5 的倍数相加,我想出了这个(很简单)

sum = 0
1.upto(999) { |i| sum += i if 0 == i%3 || 0 ==  i%5 }
sum

但我认为这会起作用,但它不起作用,有人可以告诉我我做错了什么,或者为什么它不起作用?

1.upto(999).inject(0) { |sum, i| sum + i if 0 == i%3 || 0 ==  i%5 }

谢谢!

【问题讨论】:

    标签: ruby inject


    【解决方案1】:

    inject 将块的结果作为第一个参数传递到下一次迭代。当您的if 语句为假时,您的块将返回nil,然后以sum 的形式传回。

    要得到正确答案,该块应该在它为假时返回当前总和:

    1.upto(999).inject(0) { |sum, i| (0 == i%3 || 0 ==  i%5) ? sum + i : sum }
    

    【讨论】:

      【解决方案2】:
      1.upto(999).inject(0) { |sum, i| sum += i if 0 == i%3 || 0 ==  i%5; sum }
      

      也可以使用(注意+=)。

      【讨论】:

      • 感谢您的替代答案。这更接近我的初始设置,所以我可能会这样做(对我来说更具可读性),由于错误的解释,我接受了第一个答案 - “啊哈!”对我有帮助的时刻
      【解决方案3】:

      补充答案:如果您要解决欧拉问题,您应该开始构建自己的可重用代码扩展。在这种情况下,第一个扩展名将是 Enumerable#sum:

      module Enumerable
        def sum
          inject(0, :+)
        end
      end
      

      现在您可以编写一个分离总结条件的解决方案(您可以大声朗读它,这是有道理的,这是典型的函数式/声明式风格):

      1.upto(999).select { |x| x % 3 == 0 || x % 5 == 0 }.sum
      

      你甚至可以更进一步,创建Fixnum#divisible_by?,这样你就可以写:

      1.upto(999).select { |x| x.divisible_by?(3) || x.divisible_by?(5) }.sum
      

      更多:这不是问题,但稍后严格实现(使用数组的那些)将需要太多内存。试试laziness:

      require 'lazy'
      1.upto(999).lazy.select { |x| x % 3 == 0 || x % 5 == 0 }.sum
      

      【讨论】:

      • 这是很棒的信息。我将按照其中的几个问题进行跟进,并且我看到了该建议的有用性。谢谢!
      【解决方案4】:

      或者,使用& proc 来处理self。

      (1..999).select{|x| x%3==0||x%5==0}.inject &:+
      

      【讨论】:

        【解决方案5】:

        (1..999).to_a.keep_if{|d| d%3 == 0 || d%5 == 0}.reduce(:+) 以确保完整性。

        【讨论】:

          猜你喜欢
          • 2012-08-05
          • 1970-01-01
          • 2019-11-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多