2012-05-23 11 views
11

最初のプロジェクトオイラーの質問やって:1と1000年の間3と5の倍数を加算し、私はこの(非常に簡単)を思い付いたブロックに条件付きでrubyを注入しますか?

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回答ありがとうございます。これは私の初期設定に近いので、私はおそらくこの方法で(私にはもっと読みやすい)、エラーの説明のために最初の答えを受け入れました - 「aha!」私に瞬間を助けた – 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(:+)については、

関連する問題