【问题标题】:How to use a for loop on an array in Ruby如何在 Ruby 中的数组上使用 for 循环
【发布时间】:2017-05-18 16:15:48
【问题描述】:

我需要使用for 循环从more_stuff 数组中取出最后四个字符串。

这是我的代码:

# assigns string Apples Oranges Crows Telephone Light Sugar to variable 
ten_things
ten_things = "Apples Oranges Crows Telephone Light Sugar"

# prints Wait there are not ten things on that list. Let's fix that.
puts "Wait there are not 10 things in that list. Let's fix that."

# first seperates string ten_things into an array at space character, then 
# assigns the new array to variable stuff
stuff = ten_things.split(' ')
# assigns array to more stuff with strings, Day, Night, Song, Frisbee, Girl, 
# and Boy
more_stuff = ["Day", "Night", "Song", "Frisbee", "Corn", "Banana", "Girl", 
"Boy"]

# using math to make sure there's 10 items

# assigns fifth through eighth elements in array more_stuff to array stuff_3
stuff_3 = more_stuff[4..8]
# prints array stuff_3 in brackets
puts "#{stuff_3}"
# for all strings in stuff_3
stuff_3.each do |stuff_3|
  # pops the last item off of stuff_3
  next_one = stuff_3.pop
  # puts adding (next_one)
  puts "Adding #{next_one}"
  # adds (next_one) to array stuff
  stuff.push(next_one)
# ends for loop
end

这也是我从 Powershell 运行时出现的错误:

Wait there are not 10 things in that list. Let's fix that.
["Corn", "Banana", "Girl", "Boy"]
ex38for.rb:17:in `block in <main>': undefined method `pop' for "Corn":String 
(NoMethodError)
    from ex38for.rb:16:in `each'
    from ex38for.rb:16:in `<main>'

我很困惑 for 循环的工作原理,特别是 each 以及在数组命令中放置内容的位置。

【问题讨论】:

    标签: arrays ruby for-loop


    【解决方案1】:

    pop 的作用是取数组中的最后一个元素或值(使用时不指定元素个数):

    p stuff_3.pop
    # => "Boy"
    p stuff_3.pop(2)
    # => ["Banana", "Girl"]
    

    但在您的情况下,您尝试将 pop 与主数组内的元素一起使用。

    如果您在 each 方法之外检查它:

    puts stuff_3.pop
    # => Boy
    

    然后将打印Boy,因为它是您声明为more_stuff[4..8]stuff_3 数组中的最后一个元素:

    stuff_3 = more_stuff[4..8]
    p stuff_3
    # => ["Corn", "Banana", "Girl", "Boy"]
    

    但是,当您执行stuff_3.each do |stuff_3| 时,您将使用相同的名称stuff_3 来访问该数组中具有相同名称的每个元素。所以你会得到undefined method 'pop' for "Corn":String 错误,因为pop 正在等待array,如果你遍历stuff_3 中的每个元素,你就会得到String 元素。

    一个可能的解决方案是,当您将eachstuff_3 数组一起使用时,您使用不同的名称来访问元素,也许就像stuffs,这会给您“添加男孩”和“添加女孩” ”。

    或者也许任何词来引用 stuff_3 中的元素与这个不同的元素都可以工作,因为你没有访问这些元素,你也可以使用 _ 来指定它们没有被使用:

    stuff_3.each do |_|
      next_one = stuff_3.pop
      puts "Adding #{next_one}"
      stuff.push(next_one)
    end
    

    在推送元素之前这将是stuff

    ["Apples", "Oranges", "Crows", "Telephone", "Light", "Sugar"]
    

    之后:

    ["Apples", "Oranges", "Crows", "Telephone", "Light", "Sugar", "Boy", "Girl"]
    

    【讨论】:

    • 当然有很多东西可以作为建议添加,但最好使用讨论聊天,或者指定你想要做什么以及你想要做什么关注答案。
    【解决方案2】:

    您正在隐藏外部变量:

    stuff_3.each do |stuff_3|
      stuff_3.pop
    

    在此代码块中,“内部”stuff_3 变量优先于“外部”stuff_3 变量。

    这就是您看到错误消息的原因:

    未定义的方法 `pop' for "Corn":String

    像这样遮蔽外部变量通常被认为是不好的做法,因为它会导致代码混乱和“意外”行为(就像您在此处发现的一样!)。一个简单的解决方法是只使用不同的变量名:

    stuff_3.each do |stuff_3_item|
      stuff_3.pop
    

    ...虽然我认为你在这里实际尝试做的事情应该写得有点不同 - 例如

    stuff_3.each do |stuff_3_item|
      puts "Adding #{stuff_3_item}"
      stuff.push(stuff_3_item)
    end
    

    【讨论】:

      【解决方案3】:

      让我们专注于这部分代码:

      stuff_3.each do |stuff_3|
        # pops the last item off of stuff_3
        next_one = stuff_3.pop
        # puts adding (next_one)
        puts "Adding #{next_one}"
        # adds (next_one) to array stuff
        stuff.push(next_one)
      # ends for loop
      end
      

      此代码:stuff_3.each do |stuff_3| 是一个循环,它获取 stuff_3 中的每个项目,将其保存到局部变量(您也称为 stuff_3)并使用它执行以下代码。

      因此,当您调用stuff_3.pop 时,您实际上是在仅包含一项的局部变量上调用pop,而不是包含所有项的数组。因此,您会收到错误消息:

      “Corn”的未定义方法 `pop':String

      这告诉您,您正在对单个项目(在本例中为字符串“Corn”)调用 pop,而不是您预期的一系列项目。

      解决此问题的一种方法是像这样更改您的代码:

      stuff_3.each do |next_one|
        # puts adding (next_one)
        puts "Adding #{ next_one }"
        # adds (next_one) to array of stuff
        stuff.push(next_one)
      # ends for loop
      end
      

      此代码将遍历stuff_3 中的每个项目并将其添加到stuff。但它的工作方式可能与您预期的不同:

      • stuff_3.each 会从头到尾遍历项目,而 pop 会先获取最后一个项目,这意味着此代码将以相反的顺序将项目添加到您的数组中。
      • stuff_3.each 遍历项目而不删除它们,而 pop 将删除每个项目,最终将 stuff_3 数组留空。

      如果您不想要这些变化,您仍然可以像这样使用pop

      stuff_3.times do |i|
        #pops the last item off of stuff_3
        next_one = stuff_3.pop
        # puts adding (next_one)
        puts "Adding #{next_one}"
        # adds (next_one) to array of stuff
        stuff.push(next_one)
      # ends for loop
      end
      

      此代码使用stuff_3.times 执行循环的次数与 stuff_3 中的项目数一样多。因此,如果 stuff_3 中有 3 个项目,则循环执行 3 次。变量i 是一个计数器,从0 开始,每次执行循环时向上计数。在这种情况下,times 的工作方式更像传统的 for 循环,并且上述代码的执行方式与您期望的执行方式完全相同。

      【讨论】:

        猜你喜欢
        • 2011-05-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-08-11
        • 2022-08-11
        • 2019-06-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多