【问题标题】:Can't shovel string into new array in Ruby无法将字符串铲入Ruby中的新数组
【发布时间】:2020-10-06 20:44:57
【问题描述】:

我正在尝试在数组中搜索子字符串,如果该子字符串存在,则将其铲入一个新数组中。我遇到的问题是它不断返回此错误消息:

`block in substrings': undefined method `<<' for nil:NilClass

我已经通过打印验证了方法中的index不是nil。我还做了index == nil 仔细检查。

我在这里错过了什么?

提前感谢您的帮助!

new_array = []

def substrings(word, array)

  new_array = array.each do |index|

    if index.include? (word)

      p index
      p index == nil

      new_array << index

    end
  end
end


dictionary = ["below", "down", "go", "going", "horn", "how", "howdy", "it", "i", "low", "own", "part", "partner", "sit"]

substrings("i", dictionary)

【问题讨论】:

    标签: arrays ruby string substring


    【解决方案1】:

    你基本上结合了两种不同的方法来解决这个问题。第一种是将循环数组的结果分配给new_array,但在这种情况下,new_array 变量不能在块内使用。

    所以你可以选择先创建变量,像这样

    new_array = []
    
    array.each do |index| 
      if index.include?(word)
        new_array << index
      end
    end
    

    或者,您可以使用一种称为reduce 的方法,该方法采用更实用的编程方法。可能是这样的

    new_array = array.reduce([]) do |arr, index| 
      if index.include?(word)
        arr << index
      else
        arr
      end
    end
    

    reduce 所做的是块参数arr 始终设置为前一个块执行的返回值。这可以使语法比它必须的长一点,所以 Ruby 还有一种替代方法来减少,称为each_with_object,它做同样的事情,但是通过改变相同的变量,而不是要求返回值。我实际上更喜欢这种方式,并会这样解决。

    new_array = array.each_with_object([]) do |index, arr| 
      arr << index if index.include?(word)
    end
    

    【讨论】:

      【解决方案2】:

      我想扩展一下@DanneManne 给出的(正确)答案:虽然您可以从内部块中访问外部块中的局部变量是正确的,但您不能在def 中执行此操作,并且在您的示例中是不必要的,因为您可以在方法主体内初始化 new_array 并将其作为结果返回。但如果你真的需要这种构造,确实有一种解决方法:

      所以,这不起作用:

      a=5
      def f
        puts a; # WRONG. a is not known here
      end
      

      这与您预期的不同:

      a=5
      def f
        a=6
      end
      
      puts a # prints 5
      f
      puts a # prints 5 again
      

      但是如果你这样定义你的方法,它会起作用:

      a=5
      define_method(:f) do
        puts a;  # OK, refers to outer variable a
      end
      

      通过使用一个块,你创建了一个闭包,所以如果你现在做一个

      f;
      a=6;
      f
      

      按此顺序打印 5 和 6。

      【讨论】:

        【解决方案3】:

        我已经通过打印验证了方法中的index不是nil。我还做了index == nil 仔细检查。

        我在这里错过了什么?

        不是indexnil,而是new_array。错误消息说:

        undefined method `<<' for nil:NilClass
        

        并且指的是new_array &lt;&lt; index这一行。这里,&lt;&lt; 是方法,new_array 是接收器。由于某种原因,new_arraynil

        你可能认为new_array[],因为你明确地说了new_array = []。但是方法有自己的局部变量范围。如果你在方法之外定义了一个局部变量,它在方法内部将不可用,反之亦然。

        通常当引用一个未定义的变量时,你会得到:

        undefined local variable or method `new_array'
        

        但在这里,第二个作业隐藏了实际问题:

          new_array = array.each do |index| 
          ^^^^^^^^^^^
        

        当 Ruby 遇到这一行时,它会立即创建一个初始值为 nil 的局部变量 new_array。 (局部变量是在解析行时创建的,而不是在赋值时创建的)


        要获得预期的结果,您必须将new_array = [] 移入方法,摆脱new_array = array.each { ...} 的赋值并在最后返回new_array

        def substrings(word, array)
          new_array = []
        
          array.each do |index|
            if index.include?(word)
              new_array << index
            end
          end
        
          new_array
        end
        

        变量名称有点随意,甚至可能会产生误导。拥有index.include?(word) 看起来您正在将数字索引与字符串进行比较。我会使用这样的东西:

        def substrings(substring, words)
          result = []
        
          words.each do |word|
            if word.include?(substring)
              result << word
            end
          end
        
          result
        end
        

        在代码方面,您可以通过 each_with_object 将数组合并到循环中,这也将返回数组:

        def substrings(substring, words)
          words.each_with_object([]) do |word, result|
            if word.include?(substring)
              result << word
            end
          end
        end
        

        但是,根据条件选择元素是一项非常常见的任务,Ruby 提供了一个专用方法 select - 您只需从块中返回 truefalse 以指示是否应选择元素:

        def substrings(substring, words)
          words.select do |word|
            word.include?(substring)
          end
        end
        
        

        【讨论】:

        • 谢谢! new_arraynil 值很有意义。我很欣赏范围的解释和澄清。
        猜你喜欢
        • 2020-02-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-09
        相关资源
        最近更新 更多