10

Project Eulerの問題#12を解決しようとしています:

三角形の数列は、自然数を加算することによって生成されます。したがって、7 番目の三角形の数は 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28 になります。最初の 10 項は次のようになります。

1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...

最初の 7 つの三角形の数の因数を挙げてみましょう。

 1: 1
 3: 1,3
 6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28

28 は、約数が 5 を超える最初の三角形の数であることがわかります。約数が 500 を超える最初の三角形の数の値は?

Rubyを使用して思いついたソリューションは次のとおりです。

triangle_number = 1
(2..9_999_999_999_999_999).each do |i|
  triangle_number += i
  num_divisors = 2 # 1 and the number divide the number always so we don't iterate over the entire sequence
  (2..( i/2 + 1 )).each do |j|
    num_divisors += 1 if i % j == 0
  end
  if num_divisors == 500 then
    puts i
    break
  end
end

9_999_999_999_999_999 のような任意の巨大な数値を使用するべきではありません。いくつかの関数型言語のように Math.INFINITY シーケンスがあればもっと良いでしょう。Rubyで遅延無限シーケンスを生成するにはどうすればよいですか?

4

10 に答える 10

11

いくつかの答えは近いですが、私は実際に無限の範囲を使用している人を見ていません。Rubyはそれらをうまくサポートします。

Inf = Float::INFINITY # Ruby 1.9
Inf = 1.0/0 # Ruby before 1.9
(1..Inf).include?(2305843009213693951)
# => true
(1..Inf).step(7).take(3).inject(&:+)
# => 24.0

あなたの場合

(2..Inf).find {|i| ((2..( i/2 + 1 )).select{|j| i % j == 0}.count+2)==42 }
=> 2880

力ずくの方法は粗雑であり、完了するまでに非常に長い時間がかかる可能性があります。

于 2011-06-16T15:08:21.873 に答える
10

Ruby >= 1.9 では、任意のシーケンスを生成する Enumerator オブジェクトを作成できます。整数の無限シーケンスを生成するものを次に示します。

#!/usr/bin/ruby1.9

sequence = Enumerator.new do |yielder|
  number = 0
  loop do
    number += 1
    yielder.yield number
  end
end

5.times do
  puts sequence.next
end

# => 1
# => 2
# => 3
# => 4
# => 5

または:

sequence.each do |i|
  puts i
  break if i >= 5
end

または:

sequence.take(5).each { |i| puts i }

プログラミング Ruby 1.9 (別名「つるはしの本」)、3rd。編、p。83には、三角数の列挙子の例があります。上記の列挙子を変更して三角数を生成するのは簡単です。私はここでそれを行いますが、それはおそらく「公正使用」が許す範囲を超えて、例をそのまま再現します。

于 2011-06-16T14:31:43.663 に答える
7

無限大は Float で定義されています (Ruby 1.9)

a = Float::INFINITY
puts a #=> Infinity
b = -a
puts a*b #=> -Infinity, just toying

1.upto(a) {|x| break if x >10; puts x}
于 2011-06-16T14:47:12.080 に答える
6

Ruby の現在のバージョンは、ジェネレーターを大幅にサポートしています。

sequence = 1.step
于 2016-08-16T09:55:23.433 に答える
3

これは単純なループとして最適です。

triangle_number = 1
i  = 1
while num_divisors < 500
  i += 1
  triangle_number += i
  # ...
end
puts i
于 2011-06-16T14:19:48.667 に答える
3

Amadanが述べたように、クロージャを使用できます:

triangle = lambda { t = 0; n = 1; lambda{ t += n; n += 1; t } }[]
10.times { puts triangle[] }

ループよりもはるかに遅いとは思わないでください。クラスオブジェクトにも状態を保存できますが、さらに入力する必要があります。

class Tri
  def initialize
    @t = 0
    @n = 1
  end

  def next
    @t += n
    @n += 1
    @t
  end
end

t = Tri.new
10.times{ puts t.next }

追加した:

longjmps が好きな方へ:

require "generator"

tri =
  Generator.new do |g|
    t, n = 0, 1
    loop do
      t += n
      n += 1
      g.yield t
    end
  end

puts (0..19).map{ tri.next }.inspect
于 2011-06-16T14:38:00.467 に答える
2

ウェインの優れた答えに基づいて、最小限の文字数で物事を行うというRubyの精神に基づいて構築されているのは、わずかに更新されたバージョンです。

sequence = Enumerator.new { |yielder| 1.step { |num| yielder.yield num } }

明らかに、元のオイラー問題は解決しませんが、整数の無限シーケンスを生成するには適しています。Ruby > 2.0 で確実に動作します。楽しみ!

于 2015-10-12T05:36:40.467 に答える
2

2018 年のクリスマスの日に、Ruby はこの問題に対するシンプルで新しいアプローチを提供する無限範囲を導入しました。

これは、範囲から最後の文字を省略することで実装されます。次に例を示します。

(1..)
(1...)
(10..)
(Time.now..)

または、Jonas Elfström のソリューションを使用して更新するには:

(2..).find { |i| ((2..( i / 2 + 1 )).select { |j| i % j == 0 }.count + 2) == 42 }

これが誰かに役立つことを願っています!

于 2019-01-03T18:04:42.360 に答える
1

ファイバー (Ruby 1.9 で追加されたと思います) は、あなたが望むものに近いと思います。ここでいくつかの情報を参照するか、ルビーファイバーを検索してください

于 2011-06-16T14:50:05.237 に答える