【问题标题】:Creating and inputting data into nested arrays - Ruby创建数据并将其输入到嵌套数组中 - Ruby
【发布时间】:2019-09-26 03:00:17
【问题描述】:

我正在尝试制作一个程序来获取名称并将它们添加到数组中。诀窍是我需要将它们存储在嵌套数组中,所以我向用户询问一个数字 - 这定义了组的数量。然后要求用户输入名称 - 然后需要对这些名称进行排序......

  • 例如,假设有三个组。
    • 第一组进入第一组。
    • 第二个人进入第二组。
    • 第三人进入第三组。
    • 第四人进入第一组。
    • 第五个人进入第二组。

我正在研究这些条件,我认为它们还不错。 但剩下的部分我很困惑......我真的不明白我是如何将它们发送到嵌套数组的。

groups = []

#enter the number of groups
puts "give me a number"
count = gets.to_i

while true do

puts 'Give me a name'
user_input = gets.chomp
groups.push(user_input)
groups.delete("stop")

if user_input == "stop"

puts "Give me a group number"
puts groups[gets.to_i]

#puts'es the names from that group

break

end
end

这似乎不是一百万英里,但我不确定我要去哪里。

count = 3
user_input = ["joe","sally","frank"]

groups = Array.new(count) {Array.new(user_input)}

任何帮助将不胜感激,对此非常非常新

【问题讨论】:

    标签: arrays ruby multidimensional-array


    【解决方案1】:

    得到组数后,说

    ngroups = 3
    

    代码将提示用户输入一系列名称,当用户没有更多名称可输入时,后跟"stop"。假设用户按指示的顺序输入以下字符串:

    "Lucy\n", "Hank\n", "Billy-Bob\n", "Trixie\n", "Veronica\n", "Roxy\n",
    "Norm\n", "Herb\n", "stop\n" 
    

    我们可以使用以下代码创建所需的数组:

    0.step.with_object(Array.new(ngroups) { [] }) do |i,a|
      print 'Please enter a name or "stop" if finished: '
      reply = gets.chomp
      break a if reply == "stop"
      a[i % ngroups] << reply     
    end
      #=> [["Lucy", "Trixie", "Norm"], ["Hank", "Veronica", "Herb"],
      #    ["Billy-Bob", "Roxy"]]
    

    请注意,我没有要求用户为每个名称输入一个组。那是因为您说名称将按组顺序分配给组,在每次将名称分配给最后一个组后从第一个组恢复。

    对于任何刚接触 Ruby 的人来说,这段代码一定看起来相当复杂。然而,它与 Ruby 非常相似,并且任何 Rubiest 在获得一些该语言的经验后都会立即理解它。让我分解步骤。耐心等待你应该能够理解发生了什么。

    Numeric#step,一个枚举器

    enum0 = 0.step #=> (0.step)
    

    如果您检查此方法的文档,您会看到没有块的0.step 返回一个枚举器,它是类Enumerator 的一个实例。枚举器在 Ruby 中非常重要。它们生成的值可以传递给其他方法或阻塞。在这里,enum0 生成以下序列:

    enum0.next #=> 0
    enum0.next #=> 1
    enum0.next #=> 2
    

    ...无限。见Enumerator#next

    同样,

    e = 21.step(by: -3) #=> (21.step(by: -3)) 
    e.next #=> 21 
    e.next #=> 18 
    
    e = 2.34.step #=> (2.34.step) 
    e.next #=> 2.34 
    e.next #=> 3.34 
    

    Enumerator#with_object

    我们实际上并不需要使用这种方法。我们可以改为编写以下代码,得到相同的结果:

    a = []
    0.step do |i|
      print 'Please enter a name or "stop" if finished: '
      reply = gets.chomp
      break a if reply == "stop"
      a[i % ngroups] << reply     
    end
    a
    

    如您所见,使用each_object 仅节省了两行代码:最后是a = []a1。这种方法——以及它的表亲,Enumerable#each_with_object,被 Ruby 编码人员广泛使用,实际上非常简单。

    另一个枚举器

    接下来我们有:

    enum1 = enum0.with_object(Array.new(ngroups) { [] })
      #=> #<Enumerator: (0.step):with_object([[], [], []])>
    

    enum1 的返回值可以看出,enum1 可以被认为是一个复合枚举器,尽管 Ruby 没有这样的正式概念。让我们看看这个枚举器生成什么值:

    enum1.next #=> [0, [[], [], []]] 
    enum1.next #=> [1, [[], [], []]] 
    enum1.next #=> [2, [[], [], []]] 
    

    您会看到生成的每个值都是一个由两个元素组成的数组,第一个是从零开始的计数器,第二个是一个由三组组成的数组。这些组现在是空的,但随着计算的进行,它们将被填写。

    如果我们希望我们现在可以将原始代码编写如下1

    enum1.each do |i,a|
      print 'Please enter a name or "stop" if finished: '
      reply = gets.chomp
      break a if reply == "stop"
      a[i % ngroups] << reply     
    end
    

    Enumerator#each

    enum1生成的元素传递给块

    当第一个元素生成并传递给块时,块变量ia被赋值如下:

    i, a = enum1.next #=> [0, [[], [], []]] 
    i #=> 0 
    a #=> [[], [], []]   
    

    enum1.next 返回的数组分解为其组件的过程称为array decomposition。它是一个强大而有价值的工具。

    我们现在可以执行块操作了。

    print 'Please enter a name or "stop" if finished: '
    reply = "Lucy" # = gets.chomp
    break a if reply == "stop" # do not break
    a[i % ngroups] << reply     
      #=> a[0 % 3] << "Lucy"
      #=> a[0] << "Lucy"
      #=> ["Lucy"]
    

    接下来enum1 生成它的第二个值并将其传递给块,将值分配给块变量并执行块操作。

    i, a = enum1.next #=> [1, [["Lucy"], [], []]] 
    i #=> 1 
    a #=> [["Lucy"], [], []]   
    

    请注意,a 已更新以反映 "Lucy" 已附加到 a[0]。继续,

    print 'Please enter a name or "stop" if finished: '
    reply = "Hank" # = gets.chomp
    break a if reply == "stop" # do not break
    a[i % ngroups] << reply
      #=> a[1 % 3] << "Hank"
      #=> a[1] << "Hank"
      #=> ["Hank"]
    

    现在,

    a #=> => [["Lucy"], ["Hank"], []]
    

    其余的计算类似。

    1.在运行以下命令之前,我需要执行 enum1.rewind 来重新初始化枚举器。见Enumerator#rewind

    【讨论】:

    • 非常感谢您的帮助!我在使用你给出的第一个例子时遇到了麻烦——它工作得很好,但我不知道如何访问数组,它叫什么?如果我想说访问第二个数组,我会怎么做?你给的0.step do |i|在我脑海中最有意义,但它不会为我运行。
    • 我明天会回复你,但与此同时,请更具体地了解o.step do |i|“不会为我竞选”。是否引发异常?如果是这样,错误消息是什么?错误发生在哪一行?您使用的是哪个版本的 Ruby?
    • 啊抱歉!我正在使用 repl.it - 2.5.0 undefined method block in <main>' (repl):5:in step' (repl):5:in &lt;main&gt;'
    【解决方案2】:

    首先,你必须根据给定的数字创建嵌套数组:

    puts 'Enter number of groups'
    count = gets.to_i
    groups = Array.new(count) { [] }
    

    如果用户输入 3,您将拥有一个包含 3 个其他数组的数组:

    groups = Array.new(3) { [] }
    #=> [[], [], []]
    

    Array.new 使用 块形式 很重要,因此每个内部数组都是一个单独的实例。 (请参阅文档中的“常见问题”)

    有了嵌套结构,我们可以将名称附加到内部数组。通过使用“计数器”变量i 并推送到group[i]

    puts 'Enter names or "stop" when done'
    
    i = 0                  # start at 0
    loop do
      user_input = gets.chomp
      break if user_input == 'stop'
      groups[i].push(user_input)
    
      if i < count - 1
        i += 1             # increment
      else
        i = 0              # start over
      end
    end
    

    或者——更优雅——通过cycle

    puts 'Enter names or "stop" when done'
    
    groups.cycle do |group|
      user_input = gets.chomp
      break if user_input == 'stop'
      group.push(user_input)
    end
    

    【讨论】:

    • 我用loop 试过你的代码,但它不能正常工作
    • 你修好了。现在好了。
    • @mechnicov 我硬编码了上限,即2 而不是count - 1。是之前示例的后续错字。感谢您的提醒!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-07
    • 2021-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-13
    相关资源
    最近更新 更多