9
votes

Itérer sur une séquence infinie en rubis

J'essaie de résoudre le problème du projet Euler N ° 12:

La séquence des numéros de triangle est générée en ajoutant le naturel Nombres. Donc le 7ème numéro triangle serait 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28. Les dix premiers termes seraient: p>

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


3 commentaires

Num_Divisors == 500 doit être modifié en Num_Divisors> 500 . Vous n'avez pas la preuve qu'il y en a un qui a exactement 500 diviseurs. En fait, cela peut être la raison pour laquelle votre programme fonctionne pour toujours. FAIGNEURMORE, la question ne demande pas une avec 500, mais la première sur 500. Lisez attentivement la question.


(Node latéral) Obtenez des numéros de triangle avec N * (N + 1) / 2 et vous n'avez pas besoin d'accumuler des valeurs ...


Note latérale: N * (N + 1) / 2 Facteurs proprement en deux nombres mutuellement premiers ...


10 Réponses :


3
votes

Ce serait mieux comme une simple boucle.

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


3 commentaires

Ce n'est pas ce que je cherche exactement, je cherchais une solution plus rubish non c ++ comme. J'aimerais vraiment savoir comment je peux générer une série infinie.


Ruby n'a pas vraiment d'évaluation paresseuse que si vous le simulez avec des fermetures, et je pense que cela serait très lent (Haskell est optimisé pour ce genre de chose). Sans évaluation paresseuse, vous ne recevez pas de ruisseaux infinis. Je ne pense pas qu'il n'y ait rien d'un peu abusifike ici - utilisez l'outil approprié pour le travail. Mais si vous voulez vraiment ceux-ci, voici une implémentation: Chneukirchen .org / blog / archive / 2005/05 / ...


Ceci est une solution rubis parfaitement valide et non du tout "C ++ ish". Bien sûr, je comprends ce que vous voulez bien sûr, vous aimeriez savoir si vous pouvez le faire plus jolie - rien de mal à cela - et cela vous permet d'apprendre un peu de rubis itérateurs ... Mais je vous donnerai un indice pour les futures solutions d'Euler de projet: Parfois, le seul moyen de le faire courir dans la minute consiste à utiliser des variables locales comme ci-dessus, car la méthode "rubyine" est en fait beaucoup plus lente . ;)



10
votes

in Ruby> = 1.9, vous pouvez créer un objet d'énumérateur qui donne la séquence que vous aimez. Voici un qui donne une séquence infinie d'entiers: xxx

ou: xxx

ou: xxx

Programmation Ruby 1.9 (AKA "Le livre Pickaxe "), 3ème. ed., p. 83, a un exemple d'un énumérateur pour les nombres triangulaires. Il devrait être facile de modifier l'énumérateur ci-dessus pour générer des nombres triangulaires. Je le ferais ici, mais cela reproduisait l'exemple Verbatim, probablement plus que "l'utilisation équitable".


2 commentaires

Cela semble être plus proche de ce que je voulais, merci. Y a-t-il un moyen de pouvoir l'utiliser dans ma boucle ci-dessus. Ou puis-je utiliser quelque chose comme [code] pendant que la séquence [/ code] pour réaliser cette boucle infinie jusqu'à ce qu'il soit satisfait.


@nikhil, vous pouvez utiliser chaque avec l'énumérateur. Exemple ajouté. Vous voulez probablement modifier l'énumérateur pour générer des nombres triangulaires, qui devraient être faciles.



3
votes

Comme AMADAN mentionné, vous pouvez utiliser des fermetures:

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



7
votes

Infinity est défini sur 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}


3 commentaires

Je pense que c'est ce que je voulais ici, c'est vraiment cool des idées sur la manière dont quelque chose est réellement mis en œuvre?


Matz Ruby est écrit en C, qui soutient l'infini (et la Nan). Je suppose que Ruby utilise simplement les routines C.


Dans Ruby <1.9 Créez votre propre infini: 1.0 / 0



1
votes

1 commentaires

J'ai toujours détesté Longjmps. Vous pouvez utiliser des générateurs dans R 1.8.7 avec un effet similaire.



10
votes

Plusieurs réponses sont proches mais je ne vois aucune personne utilisant des gammes infinies. Ruby les prend bien bien. XXX PRE>

Dans votre cas P>

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


5 commentaires

Pourriez-vous suggérer quelle approche je devrais utiliser à la place, je ne peux penser que cette méthode de force brute. Y a-t-il des biens mathématiques des diviseurs qui peuvent aider à la place?


Vous trouverez peut-être quelque chose à mathworld.wolfram.com/divisor.html , mais il semble qu'il n'y ait pas de Formule "magique".


Venez penser à cela, il se sent assez clair qu'il n'y a pas de bien connu, car cela identifierait des nombres premiers.


Ce problème continue de m'éloigner. J'ai tout mais abandonné à l'arrivée d'une solution à cela.


"Si vous prenez en compte un nombre dans ses facteurs d'alimentation principaux, le nombre total de facteurs est trouvé en ajoutant un à tous les exposants et en multipliant ces résultats ensemble. Exemple: 108 = 2 ^ 2 * 3 ^ 3, donc le nombre total de Les facteurs sont (2 + 1) * (3 + 1) = 3 * 4 = 12. Assez sûr, les facteurs de 108 sont 1, 2, 3, 4, 6, 9, 12, 18, 27, 36, 54, et 108. " - mathforum.org/library/drmath/view/57151.html



2
votes

Bâtir sur l'excellente réponse de Wayne et dans l'esprit de rubis de faire des choses avec le moins de caractères ici est une version légèrement mise à jour: xxx

évidemment, ne résout pas le problème d'Euler original Mais est bon pour générer une séquence infinie d'entiers. Fonctionne définitivement pour Ruby> 2.0. Profiter!


0 commentaires

6
votes

Versions currrent des générateurs de support Rubis lourdement:

sequence = 1.step


2 commentaires

Pour développer sur cela, 1.step renvoie un énumérateur, qui peut ensuite être chaîné, comme ceci: 1.step.each {| i | met i; Break Si i> 10} . Vous pouvez également utiliser prendre pour obtenir les premiers n chiffres: 1.step.take (n) => [1, 2, 3, 4, 5] .


@Brainbag 1.step {| i | met i; Casser si i> 10} est le même (no chacun ).



4
votes

dans Ruby 2.6 Cela devient beaucoup plus facile: xxx

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


0 commentaires

2
votes

Le jour de Noël 2018, Ruby a introduit le Interminable gamme , fournissant une nouvelle approche simple de ce problème.

Ceci est mis en œuvre en envisageant le caractère final de la gamme, par exemple: P>

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


0 commentaires