数组被解释为Fixnum

时间:2018-04-10 07:51:17

标签: arrays ruby 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)

这应该返回所有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函数在第一种情况下将我的数组解释为Fixnum?

2 个答案:

答案 0 :(得分:2)

问题在于递归调用:

rec_sum(num_arr.shift)

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

rec_sum(num_arr[1..-1])

rec_sum(num_arr.tap(&:shift))

对于初学者来说,后者[可能]看起来太麻烦了,但这是一种非常常见的红宝石方法:Object#tap使接收器产生阻塞,返回接收器。在一个块内(num_arr.tap(&:shift)num_arr.tap { |a| a.shift }的简写,我们通过将元素移出来改变数组,并将其作为结果返回。

答案 1 :(得分:0)

mudasobwa already explained为什么使用mic = AKMicrophone() mic.stop() fft = AKFFTTap.init(mic) micMixer = AKMixer(mic) micBooster = AKBooster(micMixer) micBooster.gain = 0 do { recorder = try AKNodeRecorder(node: micMixer) if let file = recorder.audioFile { player = try AKAudioPlayer(file: file) player.looping = false player.completionHandler = playingEnded } mainMixer = AKMixer(player, micBooster) AudioKit.output = mainMixer //THIS IS WHERE IT CRASHES! } catch { //debug prints here don't get printed throw error } 没有给出预期的结果。除此之外,你的代码在某种程度上是单一的。

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

true

(1..1000).select { |i| i % 3 == 0 || i % 5 == 0 } #=> [3, 5, 6, 9, 10, 12, ...] 中,您检查rec_sum。虽然这有效,但您正在创建一个空的一次性数组。要确定数组是否为空,您应该调用它的empty?

if num_arr == []

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

if num_arr.empty?
  # ...
end

可以通过将否定索引传递给[]来缩写:

num_arr[1..num_arr.last]

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

num_arr[1..-1]

从数组中获取第一个和剩余元素的另一个选项是Ruby的array decomposition功能(请注意num_arr[0] + rec_sum(num_arr[1..-1]) # vs num_arr.first + rec_sum(num_arr.drop(1)) ):

*

您还可以考虑使用guard clause提前从方法返回:

def rec_sum(num_arr)
  if num_arr.empty?
    0
  else
    first, *remaining = num_arr
    first + rec_sum(remaining)
  end
end

编写递归方法非常适合学习目的,但Ruby也有内置的sum方法:

def rec_sum(num_arr)
  return 0 if num_arr.empty?
  first, *remaining = num_arr
  first + rec_sum(remaining)
end

或 - 因为您使用的是较旧的Ruby版本 - inject

multi_gen.sum #=> 234168