我正在学习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
可以对这段代码进行哪些改进?
答案 0 :(得分:4)
正如其他人所说,Rubyists将使用方法或阻止方式而不是lambdas。
Ruby的Enumerable
是一个非常强大的混合,所以我觉得在这里建立一个与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的新用户。如果使用的是早期版本,请使用1.0/0
,require 'backports'
或执行loop
。首先检查块是否通过,可以改进each
;你会经常看到这样的事情:
def each
return to_enum __method__ unless block_given?
# ...
答案 1 :(得分:2)
不是一次性解决问题,而是查看问题的各个部分可能会帮助您更好地理解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
这也可以使用另一种称为inject的可枚举方法来完成,该方法将从前一个元素返回的内容传递给当前元素。使用它,您可以在一行中得到总和。在这个例子中,我使用1.upto(10),它的功能与(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.下一个sum = 3,x = 3,(sum + 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)
答案 2 :(得分:0)
看起来你来自编写Ocaml或其他功能语言。在Ruby中,您可能希望使用更多def
来定义方法。 Ruby就是要保持干净。但这也可能是个人偏好。
而不是loop do
你可以while (faction_count(traingle_number(n)) < 500) do
而不是一些可能对一行来说太多了。