这个问题更像ruby般的解决方案?

我正在学习ruby并通过解决Project Euler的问题来练习它。

这是我对问题12的解决方案。

# Project Euler problem: 12 # What is the value of the first triangle number to have over five hundred divisors? require 'prime' triangle_number = ->(num){ (num *(num + 1)) / 2 } factor_count = ->(num) do prime_fac = Prime.prime_division(num) exponents = prime_fac.collect { |item| item.last + 1 } fac_count = exponents.inject(:*) end n = 2 loop do tn = triangle_number.(n) if factor_count.(tn) >= 500 puts tn break end n += 1 end 

可以对这段代码进行任何改进吗?

而不是一次解决问题,查看问题的各个部分可能会帮助您更好地理解ruby。

第一部分是找出三角形的数字。 由于这使用了自然数序列,因此您可以使用ruby中的范围来表示它。 这是一个例子:

 (1..10).to_a => [1,2,3,4,5,6,7,8,9,10] 

ruby中的数组被认为是可枚举的,而ruby提供了许多枚举数据的方法。 使用此概念,您可以使用each方法迭代此数组,并传递一个对数字求和的块。

 sum = 0 (1..10).each do |x| sum += x end sum => 55 

这也可以使用另一种称为注入的可枚举方法来完成,该方法将从前一个元素返回的内容传递给当前元素。 使用它,您可以在一行中得到总和。 在这个例子中,我使用1.upto(10),它在function上与(1..10)相同。

 1.upto(10).inject(0) {|sum, x| sum + x} => 55 

单步执行此操作,第一次调用它时,sum = 0,x = 1,因此(sum + x)= 1.然后它将此传递给下一个元素,因此sum = 1,x = 2,(sum + x )= 3.下一个和= 3,x = 3,(和+ x)= 6. sum = 6,x = 4,(sum + x)= 10.等等

这只是这个问题的第一步。 如果您想以这种方式学习语言,您应该接近问题的每个部分,并了解适合学习该部分的内容,而不是解决整个问题。

经过改造的解决方案(尽管效率不高)

 def factors(n) (1..n).select{|x| n % x == 0} end def triangle(n) (n * (n + 1)) / 2 end n = 2 until factors(triangle(n)).size >= 500 puts n n += 1 end puts triangle(n) 

正如其他人所说,Rubyists将使用方法或阻止方式而不是lambdas。

Ruby的Enumerable是一个非常强大的mixin,所以我觉得在这里建立一个类似Prime的枚举是值得的。 所以:

 require 'prime' class Triangular class << self include Enumerable def each sum = 0 1.upto(Float::INFINITY) do |i| yield sum += i end end end end 

这是非常通用的。 检查它是否有效:

 Triangular.first(4) # => [1, 3, 7, 10] 

好。 现在您可以使用它来解决您的问题:

 def factor_count(num) prime_fac = Prime.prime_division(num) exponents = prime_fac.collect { |item| item.last + 1 } exponents.inject(1, :*) end Triangular.find{|t| factor_count(t) >= 500} # => 76576500 

备注

  • Float::INFINITY是1.9.2的新function。 使用1.0/0require 'backports'或者如果使用早期版本则执行loop
  • 可以通过首先检查块是否通过来改进each ; 你会经常看到这样的事情:

      def each return to_enum __method__ unless block_given? # ... 

看起来你来自编写Ocaml或其他function语言。 在Ruby中,您可能希望使用更多def来定义方法。 Ruby就是要保持干净。 但这也可能是个人偏好。

你可以while (faction_count(traingle_number(n)) < 500) do一个loop do而不是一些loop do但是对于一些可能对于一行来说可能太多的东西。