Pregunta

Estoy tratando de resolver el Proyecto Euler Problema #12:

La secuencia de números de triángulo se genera agregando los números naturales. Entonces, el séptimo número de triángulo sería 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28. Los primeros diez términos serían:

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

Enumeremos los factores de los primeros siete números de triángulo:

 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

Podemos ver que 28 es el primer número de triángulo en tener más de cinco divisores. ¿Cuál es el valor del primer número de triángulo que tiene más de quinientos divisores?

Aquí está la solución que se me ocurrió usar 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

No debería usar un gran número arbitrario como 9_999_999_999_999_999. Sería mejor si tuviéramos una secuencia de Infinity Math. como algunos lenguajes funcionales. ¿Cómo puedo generar una secuencia infinita perezosa en Ruby?

¿Fue útil?

Solución

En Ruby> = 1.9, puede crear un objeto enumerador que produce cualquier secuencia que desee. Aquí hay uno que produce una secuencia infinita de enteros:

#!/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

O:

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

Programación Ruby 1.9 (también conocido como "The Pickaxe Book"), 3er. ed., p. 83, tiene un ejemplo de enumerador para números triangulares. Debería ser fácil modificar el enumerador anterior para generar números triangulares. Lo haría aquí, pero eso reproduciría el ejemplo textual, probablemente más de lo que permite el "uso justo".

Otros consejos

Varias respuestas están cerca, pero en realidad no veo a nadie que use rangos infinitos. Ruby los apoya bien.

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

En tu caso

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

Su método de fuerza bruta es crudo y, potencialmente, puede tardar mucho en terminar.

El infinito se define en el flotador (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}

Versiones Currrent de Generadores de soporte de Ruby en gran medida:

sequence = 1.step

Esto sería mejor como un bucle simple.

triangle_number = 1
i  = 1
while num_divisors < 500
  i += 1
  triangle_number += i
  # ...
end
puts i

Como Amadan mencionó, puede usar cierres:

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

Realmente no pienses que es mucho más lento que un bucle. También puede guardar el estado en el objeto de clase, pero necesitará más tipificación:

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 }

Adicional:

Para aquellos a quienes les gustan los largos:

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

En Ruby 2.6 esto se vuelve mucho más fácil:

(1..).each {|n| ... }

Fuente: https://bugs.ruby-lang.org/issues/12912

Construir la excelente respuesta de Wayne y en el espíritu de Ruby de hacer cosas con la menor cantidad de personajes aquí hay una versión ligeramente actualizada:

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

Obviamente, no resuelve el problema original de Euler, pero es bueno para generar una secuencia infinita de enteros. Definitivamente funciona para Ruby> 2.0. ¡Disfrutar!

El día de Navidad de 2018, Ruby presentó el rango sin fin, proporcionando un nuevo enfoque simple para este problema.

Esto se implementa omitiendo el carácter final desde el rango, por ejemplo:

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

O para actualizar usando la solución de Jonas Elfström:

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

¡Espero que esto sea útil para alguien!

Creo que las fibras (agregadas en Ruby 1.9, creo) pueden estar cerca de lo que quieres. Ver aquí Para obtener información o simplemente buscar fibras de rubí.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top