我的目标是编写一个执行以下操作的方法trickysum(n)
:
该方法采用数字1到n的范围。然后,该方法在该范围内找到满足棘手资格的数字对:该对数字的乘积必须等于该范围内所有数字的总和,不包括该对。该方法然后返回符合此资格的所有数字对。这是期望:
trickysum(26)
#=>[(15, 21), (21, 15)]
这是我到目前为止的代码:
def trickysum(n)
result = []
arr = (1..n).to_a
0.upto(arr.length - 1) do |x|
0.upto(arr.length - 1) do |y|
prod = arr[x] * arr[y]
#I create a new array to delete from to not affect the original
#array. Would also love an easier way to do this :)
new_arr = arr
new_arr.delete(new_arr[x])
new_arr.delete(new_arr[y])
sum = new_arr.inject(:+)
if sum == prod
result << "(#{arr[x]},#{arr[y]})"
end
end
end
result
end
我一遍又一遍地查看这段代码,无法弄清楚为什么我收到以下错误:
nil can't be coerced into Fixnum
(repl):7:in `*'
(repl):7:in `block (2 levels) in trickysum'
(repl):6:in `upto'
(repl):6:in `block in trickysum'
(repl):5:in `upto'
(repl):5:in `trickysum'
(repl):20:in `<main>'
我哪里错了?
答案 0 :(得分:3)
替换:
new_arr = arr
使用:
new_arr = arr.dup
这里发生的是您创建了arr
变量的浅拷贝。如果没有明确重复该值,new_arr
和arr
共享内存中的相同位置。
因此,当您致电new_arr.delete(new_arr[x])
和new_arr.delete(new_arr[y])
时,您不仅会改变新数组,还会改变旧数组
这意味着arr
的长度变短,因此您的外部循环超出了其最终值,您得到nil
;因此错误。
话虽如此,我会完全不同地编写这种方法,这可以避免这种微妙的错误:
def trickysum(n)
sum = (1..n).inject(:+)
(1..n).combination(2).select do |a, b|
(a * b) + a + b == sum
end
end
Ruby是非常富有表现力的语言。如果你发现自己在循环中循环,声明临时变量并附加到一组结果......那么可能是一个更优雅的解决方案:)