【问题标题】:Ruby !map not changing object typeRuby !map 不改变对象类型
【发布时间】:2013-04-10 02:11:52
【问题描述】:

我一直在研究几个项目 Euler questions 来帮助学习编程,想知道是否有人可以向我解释一下。

我有一串数字,我试图找出序列中任意五个数字中最大的乘积。这是我目前所拥有的:

temp = series.split(//).map!{|x| x.to_i}
len = temp.length
maxprod = 1
0.upto(len-4) do |x|
    num = (temp[x] * temp[x+1] * temp[x +2] * temp[x+3] * temp[x+4])

    if num > maxprod
        maxprod = num
    end

end 

puts maxprod

temp[0].class 返回一个 fixnum,但是,当我运行代码时,我得到一个错误“* : nil can't be coerced into FixNum (TypeError)”

谢谢

【问题讨论】:

    标签: ruby


    【解决方案1】:

    这是因为map 返回一个数组。 map! 返回 nil。然后,您将 map! 返回的 nil 放入 temp

    它们仍然在split 结果的每个元素上运行块,但是当您希望将结果放入变量时,您应该始终使用map。这是一个很容易绊倒你的微妙之处。

    改变

    temp = series.split(//).map!{|x| x.to_i}
    

    temp = series.split(//).map{|x| x.to_i}
    

    奖励:

    您可以使用与符号& 和方法名称作为符号将块传递给map

    temp = series.split(//).map(&:to_i)
    

    编辑:

    根据您的 cmets,在将数组元素相乘时,您仍然会遇到错误。这可能是因为您的 temp 数组没有您认为的那么多元素。尝试使用当前没有任何内容的索引访问数组会导致nil

    temp = [1]
    temp[0] #=> 1
    temp[1] #=> nil
    temp[0] * temp[1] #=> TypeError: nil can't be coerced into FixNum 
    

    您提到使用temp[1].to_i 解决了这个问题。那是因为nil 可以转换为整数。

    nil.to_i #=> 0
    

    我会检查temp 的结果,以确保它包含您认为它包含的内容。 您可能还想查看Enumerable#each_slice,它采用数组的一个子集并在一个块中处理它。

    nums = %w{08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08}.map(&:to_i)
    nums.each_slice(4) {|a| puts a.inject(:*)}
    

    【讨论】:

    • 为了扩展这一点,ruby 范式是破坏性方法(改变对象内部状态的方法)往往有一个 !后缀。在你的情况下,地图!表示它会修改您引用的任何可枚举对象的内部结构,而 map 从原始对象创建一个新的、已更改的对象并返回它。
    • 我进行了更改,但仍然收到相同的错误。我确实将循环更改为“temp[x].to_i * temp[x+1].to_i ...”,这似乎有效(只是似乎重复)。
    • 这可能是因为temp 没有像您想象的那样包含那么多元素。请注意,如果数组只有 1 个元素,temp[1] == nil。因此,temp = [1]; temp[0] * temp[1] 会给你你得到的错误。 to_i 为您工作的原因是因为 nil.to_i == 0
    • 感谢您的帮助和详尽的解释。
    • @CharlesCaldwell map! 返回nil。我无法理解你的说法。
    猜你喜欢
    • 2015-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-20
    • 2021-11-06
    • 2021-08-17
    相关资源
    最近更新 更多