2012-05-23 99 views
11

做的第一个项目欧拉问题:3和5倍数总结1和1000之间,我想出了这个(很简单)红宝石注入有条件的块?

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 } 

谢谢!

回答

22

inject将块的结果作为第一个参数传递给下一次迭代。当您的if声明为false时,您的区块将返回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 } 

也将工作(注意+=)。

+0

感谢您的alt答案。这更接近我的初始设置,所以我可能会这样做(更易读),我接受了第一个答案,因为错误的解释 - '啊哈!'给我帮助的时刻 – Tonys

3

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

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

现在,您可以编写分隔summatory的条件的方案(你可以大声读出来,它是有道理的,这是典型的功能/声明的风格):

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 
+0

这是很棒的信息。我将按照其中的几个问题关注它,并且看到建议的实用性。谢谢! – Tonys

2

或者,使用& PROC其中涉及自我。

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

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