首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >数组解释为Fixnum

数组解释为Fixnum
EN

Stack Overflow用户
提问于 2018-04-10 07:51:16
回答 2查看 61关注 0票数 1

我目前正在学习ruby,我编写了这段代码:

代码语言:javascript
复制
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)

这应该返回所有3倍和5倍的总和,最多可达1000倍。

但我发现了一个错误:

代码语言:javascript
复制
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>'

但当我改写成这样:

代码语言:javascript
复制
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函数将数组解释为Fixnum呢?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-04-10 08:59:28

mudasobwa 已解释为什么使用shift没有给出预期的结果。除此之外,您的代码在某种程度上是统一的。

multi_gen中,您正在创建一个空数组,并使用一个for循环向其追加元素。很少需要手动填充数组。相反,您通常可以使用Ruby的ArrayEnumerable方法来生成数组。select是一个非常常见的数组,它返回一个数组,其中包含给定块返回true的元素。

代码语言:javascript
复制
(1..1000).select { |i| i % 3 == 0 || i % 5 == 0 }
#=> [3, 5, 6, 9, 10, 12, ...]

rec_sum中,您检查if num_arr == []。虽然这样做有效,但您正在创建一个空的抛出数组。若要确定数组是否为空,应调用其empty?

代码语言:javascript
复制
if num_arr.empty?
  # ...
end

要从数组中获取其余元素,可以使用:

代码语言:javascript
复制
num_arr[1..num_arr.last]

它可以通过向[]传递负索引来缩写。

代码语言:javascript
复制
num_arr[1..-1]

还有一个drop,它看起来可能更好一些:

代码语言:javascript
复制
num_arr[0] + rec_sum(num_arr[1..-1])
# vs
num_arr.first + rec_sum(num_arr.drop(1))

从数组中获取第一个元素和其余元素的另一个选项是Ruby的阵列分解特性(注意*):

代码语言:javascript
复制
def rec_sum(num_arr)
  if num_arr.empty?
    0
  else
    first, *remaining = num_arr
    first + rec_sum(remaining)
  end
end

还可以考虑使用保护条款尽早从该方法返回:

代码语言:javascript
复制
def rec_sum(num_arr)
  return 0 if num_arr.empty?
  first, *remaining = num_arr
  first + rec_sum(remaining)
end

编写递归方法对于学习有目的的学习非常有用,但是Ruby也有一个内置的sum方法:

代码语言:javascript
复制
multi_gen.sum #=> 234168

或者-由于您使用的是较旧的Ruby版本- inject

代码语言:javascript
复制
multi_gen.inject(0, :+) #=> 234168
票数 0
EN

Stack Overflow用户

发布于 2018-04-10 07:54:46

问题在于递归调用:

代码语言:javascript
复制
rec_sum(num_arr.shift)

Array#shift返回移位元素,而不是剩余的数组。应该显式地将数组作为参数传递给递归调用:

代码语言:javascript
复制
rec_sum(num_arr[1..-1])

代码语言:javascript
复制
rec_sum(num_arr.tap(&:shift))

对于初学者来说,后者看起来可能太麻烦了,但这是一种非常常见的规则化方法:Object#tap将接收器生成到块中,然后返回接收器。在块内部(num_arr.tap(&:shift)num_arr.tap { |a| a.shift }的简写),我们通过将元素移出来改变数组,结果就是返回它。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49748192

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档