15

做第一个 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 }

谢谢!

4

5 回答 5

30

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

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

1.upto(999).inject(0) { |sum, i| (0 == i%3 || 0 ==  i%5) ? sum + i : sum }
于 2012-05-23T15:22:14.467 回答
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

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

require 'lazy'
1.upto(999).lazy.select { |x| x % 3 == 0 || x % 5 == 0 }.sum
于 2012-05-23T16:07:54.373 回答
2

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

(1..999).select{|x| x%3==0||x%5==0}.inject &:+
于 2012-05-23T17:41:38.130 回答
2

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

于 2012-12-22T23:14:02.177 回答
2
1.upto(999).inject(0) { |sum, i| sum += i if 0 == i%3 || 0 ==  i%5; sum }

也可以工作(注意+=)。

于 2012-05-23T15:25:46.517 回答