15

最初のプロジェクトオイラーの質問をします: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ブロックの結果を最初の引数として次の反復に渡します。ステートメントがfalseのnil場合、ブロックは戻り、その後、として返されます。ifsum

正しい答えを得るには、ブロックがfalseの場合に現在の合計を返す必要があります。

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
1.upto(999).inject(0) { |sum, i| sum += i if 0 == i%3 || 0 ==  i%5; sum }

また動作します(に注意してください+=)。

于 2012-05-23T15:25:46.517 に答える
2

(1..999).to_a.keep_if{|d| d%3 == 0 || d%5 == 0}.reduce(:+)完全を期すために。

于 2012-12-22T23:14:02.177 に答える
2

または、&自分自身をアドレス指定するprocを使用します。

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