在Ruby中的同一行中打印不同大小数组的数组元素

Posted

技术标签:

【中文标题】在Ruby中的同一行中打印不同大小数组的数组元素【英文标题】:Print elements of array of arrays of different size in same line in Ruby 【发布时间】:2018-05-18 22:59:40 【问题描述】:

也许有人可以帮我解决这个问题。我有一个数组数组。内部数组有不同的大小(从 2 到 4 个元素)。

letters = [["A", "B"],["C", "D", "F", "G"],["H", "I", "J" ]] 

我试图在同一行中打印每个数组作为第一列元素 [0] 和元素 [1] 加入,作为第二列元素 [0]、元素 [1]、元素 [2] 作为第三列加入列元素[0]、元素[1]、元素[3] 已加入。元素 2 和 3 并不总是存在。

我想要得到的输出是这样的:

AB
CD CDF CDG
HI HIJ

我正在这样做,但我收到了这个错误。

letters.map|x| puts x[0]+x[1] + "," + x[0]+x[1]+x[2] + "," + x[0]+x[1]+x[3]
TypeError: no implicit conversion of nil into String
        from (irb):1915:in "+"
        from (irb):1915:in "block in irb_binding"
        from (irb):1915:in "map"
        from (irb):1915
        from /usr/bin/irb:11:in "<main>"

【问题讨论】:

【参考方案1】:
letters.each do |a,b,*rest|
  puts rest.each_with_object([a+b])  |s,arr| arr << arr.first + s .join(' ')
end

打印

AB
CD CDF CDG
HI HIJ

步骤如下。

假设

letters =  [["C", "D", "F", "G"],["H", "I", "J" ]] 

然后

enum0 = letters.each
  #=> #<Enumerator: [["C", "D", "F", "G"], ["H", "I", "J"]]:each>

生成此枚举器的第一个元素并传递给块,并为三个块变量赋值。

a, b, *rest = enum0.next
  #=> ["C", "D", "F", "G"]
a
  #=> "C"
b 
  #=> "D"
rest
  #=> ["F", "G"]

接下来,我们得到

enum1 = rest.each_with_object([a+b])
  #=> rest.each_with_object(["CD"]) 
  #=> #<Enumerator: ["F", "G"]:each_with_object(["CD"])>

生成此枚举器的第一个元素并传递给块,并为块变量赋值。

s, arr = enum1.next
  #=> ["F", ["CD"]]
s
  #=> "F"
arr
  #=> ["CD"]

现在执行块计算。

arr << arr.first + s
  #=> arr << "CD" + "F"
  #=> ["CD", "CDF"] 

生成enum1的第二个和最后一个元素并传递给块,并为块变量赋值并计算块。

s, arr = enum1.next
  #=> ["G", ["CD", "CDF"]]
arr << arr.first + s
  #=> ["CD", "CDF", "CDG"]

当我们尝试从enum1 生成另一个元素时,我们得到

enum1.next
  #StopIteration: iteration reached an end

Ruby 通过跳出块并返回arr 来处理异常。然后加入arr 的元素:

arr.join(' ')
  #=> "CD CDF CDG"

并打印出来。

enum0 的第二个和最后一个元素现在已生成,传递给块,并为三个块变量赋值。

a, b, *rest = enum0.next
  #=> ["H", "I", "J"]
a
  #=> "H"
b
  #=> "I"
rest
  #=> ["J"]

其余计算类似。

有些读者可能对Enumerable#each_with_object这个方法比较陌生,这个方法被广泛使用。阅读文档,但请注意,这里它产生的结果与以下编写的代码相同。

letters.each do |a,b,*rest|
  arr = [a+b]
  rest.each  |s| arr << arr.first + s 
  puts arr.join(' ')
end

通过使用each_with_object,我们可以避免使用arr = [a+b]puts arr.join(' ') 语句。这两个语句的功能当然在使用each_with_object 的行中,但是大多数Ruby 用户更喜欢将each_with_object 链接到join(' ') 时的流程。另一个区别是arr 的值仅限于each_with_object 的块,这是一种良好的编程习惯。

【讨论】:

感谢 Cary Swoveland,它工作得很好。我有点难以理解其中的逻辑。如果有机会和时间,如果您能解释一下它是如何工作的,我将不胜感激。 怀疑,我已经提供了你要求的解释。如果您是 Ruby 新手,则值得仔细研究。 非常感谢 Cary Swoveland。感谢您的详细解释。是的,我是 ruby​​ 新手,并逐步阅读您的内容。我承认我仍然有待完全理解这些步骤的一部分,但对所有看到它的人都非常有用。 怀疑,我在答案的末尾添加了更多解释。 我有问题要理解each_with_object,通过您的解释,我更好地理解了逻辑以及您使用它的原因。感谢您帮助您与他人分享您的知识,真的【参考方案2】:

看起来你想加入前两个字母,然后用剩下的取笛卡尔积。

letters.each do |arr|
   first = arr.take(2).join
   rest = arr.drop(2)
   puts [first, [first].product(rest).map(&:join)].join(" ")
end

这提供了您指定的确切输出。

【讨论】:

嗨,马克,非常感谢您的帮助。它工作完美。很高兴在实践中学习新事物,例如取放。除此之外,地图(&amp;:join)中的这种表达式是如何命名的以及它是如何工作的? map(&amp;:join)map|x| x.join 的简写。【参考方案3】:

出于好奇,Enumerable#map-only 解决方案。

letters = [["A", "B"],["C", "D", "F", "G"],["H", "I", "J" ]]

letters.map do |f, s, *rest|
  rest.unshift(nil).map  |l| [f, s, l].join .join(' ')
end.each(&method(:puts))

#⇒ AB
#  CD CDF CDG
#  HI HIJ

【讨论】:

mudasobwa 谢谢,谢谢,非常感谢收到解决此问题的另一种方法。它有助于学习。

以上是关于在Ruby中的同一行中打印不同大小数组的数组元素的主要内容,如果未能解决你的问题,请参考以下文章

C 找数组中最小的元数,找出最小数下标并返回,在主函数中打印最小数和下标?

数组 冒泡排序 打印菱形 随机生成不同的数

如何在返回数据的同一行初始化一个新的 int 数组? [复制]

数据结构_数组

LEETCODE刷题 二维数组查找

从数组中删除仅大小写不同的字符串值(Ruby)