数组解释为 Fixnum
Array interpreted as a Fixnum
我目前正在学习 ruby 我写了这段代码:
def multi_gen
s = []
for i in (3..10)
if i%3 == 0 || i%5 == 0
s<<i
end
end
return s
end
puts multi_gen
def rec_sum(num_arr)
if num_arr == []
return 0
else
num_arr.first + rec_sum(num_arr.shift)
end
end
puts rec_sum(multi_gen)
那应该return所有3和5的倍数之和达到1000。
但是我得到一个错误:
myrbfile.rb:17:in `rec_sum': undefined method `first' for 3:Fixnum (NoMethodError)
from villani.rb:17:in `rec_sum'
from villani.rb:21:in `<main>'
但是当我这样重写它时:
def multi_gen
s = []
for i in (3..10)
if i%3 == 0 || i%5 == 0
s<<i
end
end
return s
end
puts multi_gen
def rec_sum(num_arr)
if num_arr == []
return 0
else
num_arr[0] + rec_sum(num_arr[1..num_arr.last])
end
end
puts rec_sum(multi_gen)
我没有收到错误。
那么为什么我的第一个 rec_sum 函数在第一种情况下将我的 Array 解释为 Fixnum?
问题出在递归调用中:
rec_sum(num_arr.shift)
Array#shift
returns 移动的元素,而不是剩余的数组。您应该显式地将数组作为参数传递给递归调用:
rec_sum(num_arr[1..-1])
或
rec_sum(num_arr.tap(&:shift))
后者 [可能] 对初学者来说看起来太麻烦了,但这是一种非常常见的 rubyish 方法:Object#tap
将接收者交给块,返回接收者。在一个块内(num_arr.tap(&:shift)
是 shorthand 对于 num_arr.tap { |a| a.shift }
我们通过将元素移出来改变数组,并将其作为结果返回。
mudasobwa 为什么使用 shift
没有给出预期的结果。除此之外,您的代码在某种程度上是单一的。
在 multi_gen
中,您正在创建一个空数组并使用 for
循环向其追加元素。您很少需要手动填充数组。相反,您通常可以使用 Ruby 的 Array
或 Enumerable
方法之一来生成数组。 select
是一个非常常见的 - 它 returns 是一个包含给定块 returns true
:
的元素的数组
(1..1000).select { |i| i % 3 == 0 || i % 5 == 0 }
#=> [3, 5, 6, 9, 10, 12, ...]
在 rec_sum
中,您检查 if num_arr == []
。虽然这有效,但您正在创建一个空的 throw-away 数组。要判断一个数组是否为空,你应该调用它的 empty?
:
if num_arr.empty?
# ...
end
要从数组中获取剩余元素,您可以使用:
num_arr[1..num_arr.last]
可以通过将负索引传递给[]
来缩写:
num_arr[1..-1]
还有 drop
可能看起来更好一点:
num_arr[0] + rec_sum(num_arr[1..-1])
# vs
num_arr.first + rec_sum(num_arr.drop(1))
从数组中获取第一个和剩余元素的另一个选项是 Ruby 的 array decomposition 功能(注意 *
):
def rec_sum(num_arr)
if num_arr.empty?
0
else
first, *remaining = num_arr
first + rec_sum(remaining)
end
end
您也可以考虑使用 guard clause 到 return 的早期方法:
def rec_sum(num_arr)
return 0 if num_arr.empty?
first, *remaining = num_arr
first + rec_sum(remaining)
end
编写递归方法非常适合学习目的,但是 Ruby 也有一个 built-in sum
方法:
multi_gen.sum #=> 234168
或 – 因为您使用的是较旧的 Ruby 版本 – inject
:
multi_gen.inject(0, :+) #=> 234168
我目前正在学习 ruby 我写了这段代码:
def multi_gen
s = []
for i in (3..10)
if i%3 == 0 || i%5 == 0
s<<i
end
end
return s
end
puts multi_gen
def rec_sum(num_arr)
if num_arr == []
return 0
else
num_arr.first + rec_sum(num_arr.shift)
end
end
puts rec_sum(multi_gen)
那应该return所有3和5的倍数之和达到1000。
但是我得到一个错误:
myrbfile.rb:17:in `rec_sum': undefined method `first' for 3:Fixnum (NoMethodError)
from villani.rb:17:in `rec_sum'
from villani.rb:21:in `<main>'
但是当我这样重写它时:
def multi_gen
s = []
for i in (3..10)
if i%3 == 0 || i%5 == 0
s<<i
end
end
return s
end
puts multi_gen
def rec_sum(num_arr)
if num_arr == []
return 0
else
num_arr[0] + rec_sum(num_arr[1..num_arr.last])
end
end
puts rec_sum(multi_gen)
我没有收到错误。
那么为什么我的第一个 rec_sum 函数在第一种情况下将我的 Array 解释为 Fixnum?
问题出在递归调用中:
rec_sum(num_arr.shift)
Array#shift
returns 移动的元素,而不是剩余的数组。您应该显式地将数组作为参数传递给递归调用:
rec_sum(num_arr[1..-1])
或
rec_sum(num_arr.tap(&:shift))
后者 [可能] 对初学者来说看起来太麻烦了,但这是一种非常常见的 rubyish 方法:Object#tap
将接收者交给块,返回接收者。在一个块内(num_arr.tap(&:shift)
是 shorthand 对于 num_arr.tap { |a| a.shift }
我们通过将元素移出来改变数组,并将其作为结果返回。
mudasobwa shift
没有给出预期的结果。除此之外,您的代码在某种程度上是单一的。
在 multi_gen
中,您正在创建一个空数组并使用 for
循环向其追加元素。您很少需要手动填充数组。相反,您通常可以使用 Ruby 的 Array
或 Enumerable
方法之一来生成数组。 select
是一个非常常见的 - 它 returns 是一个包含给定块 returns true
:
(1..1000).select { |i| i % 3 == 0 || i % 5 == 0 }
#=> [3, 5, 6, 9, 10, 12, ...]
在 rec_sum
中,您检查 if num_arr == []
。虽然这有效,但您正在创建一个空的 throw-away 数组。要判断一个数组是否为空,你应该调用它的 empty?
:
if num_arr.empty?
# ...
end
要从数组中获取剩余元素,您可以使用:
num_arr[1..num_arr.last]
可以通过将负索引传递给[]
来缩写:
num_arr[1..-1]
还有 drop
可能看起来更好一点:
num_arr[0] + rec_sum(num_arr[1..-1])
# vs
num_arr.first + rec_sum(num_arr.drop(1))
从数组中获取第一个和剩余元素的另一个选项是 Ruby 的 array decomposition 功能(注意 *
):
def rec_sum(num_arr)
if num_arr.empty?
0
else
first, *remaining = num_arr
first + rec_sum(remaining)
end
end
您也可以考虑使用 guard clause 到 return 的早期方法:
def rec_sum(num_arr)
return 0 if num_arr.empty?
first, *remaining = num_arr
first + rec_sum(remaining)
end
编写递归方法非常适合学习目的,但是 Ruby 也有一个 built-in sum
方法:
multi_gen.sum #=> 234168
或 – 因为您使用的是较旧的 Ruby 版本 – inject
:
multi_gen.inject(0, :+) #=> 234168