给定一个(多行)字符串,其中每一行由"\n"分隔,并且不一定具有相同的长度,那么将其转换为另一个字符串的最佳方法是什么?短于最长行的行应该用空格填充(右填充表示原始行,或底填充表示输出行)对字符串应用两次操作应该是等幂模填充。
输入字符串

abc
def ghi
jk lm no

输出字符串
adj
bek
cf
  l
 gm
 h
 in
  o

最佳答案

这里有五种方法(是的,我有点忘乎所以,但我发现尝试用不同的方法来完成同样的任务对灰色细胞来说是很好的锻炼。)
#1个
一种无趣的暴力方法:

a = str.split("\n")
l = a.max_by(&:size).size
puts a.map { |b| b.ljust(l).chars }
      .transpose
      .map { |c| c.join.rstrip }.join("\n")
adj
bek
cf
  l
 gm
 h
 in
  o

#2个
此方法和随后的所有方法都避免使用ljusttranspose,并利用这样一个事实:如果e是一个空数组,e.shift返回nil并将e保留为一个空数组。(旁白:我经常伸手去寻找不存在的方法String#shift。在这里,它可以避免将每一行转换为一个字符数组的需要。)
a = str.split("\n").map(&:chars)
a.max_by(&:size).size.times.map { a.map { |e| e.shift || ' ' }.join.rstrip }

#3个
此方法和其余方法不需要计算最长字符串的长度:
a = str.split("\n").map(&:chars)
a_empty = Array(a.size, [])
[].tap { |b| b << a.map { |e| e.shift || ' ' }.join.rstrip while a != a_empty }

#4个
这种方法利用了Enumerator#lazy,这是从v2.0开始就可用的。
a = str.split("\n").map(&:chars)
(0..Float::INFINITY).lazy.map do |i|
  a.each { |e| e.shift } if i > 0
  a.map  { |e| e.first || ' ' }.join.rstrip
end.take_while { c = a.any? { |e| !e.empty? }  }.to_a

(我最初在让它工作时遇到了问题,因为我没有得到输出的元素(" o")。修复方法是添加第三行,并将a.map { |e| e.shift || ' ' }.join.rstrip后面的行更改为我现在拥有的行。我之所以提到这一点,是因为在使用lazy时,这似乎是一个常见的问题。)
#5个
最后,使用递归:
def recurse(a, b=[])
  return b[0..-2] if a.last.empty?
  b << a.map { |e| e.shift || ' ' }.join.rstrip
  recurse(a, b)
end

a = str.split("\n").map(&:chars)
recurse(a)

关于ruby - 转置字符串,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24196825/

10-13 09:21
查看更多