如何打印具有固定列宽的2D数组
我有一个数组:
animals = [ ["cats", "dogs"], ["verrylongcat", "dog"], ["shortcat", "verrylongdog"], ["cat", "dog"] ]
而且我想很好地展示它。 是否有一种简单的方法可以使柱子固定宽度,所以我得到这样的东西:
cats dogs verrylongcat dog shortcat verrylongdog cat dog
animals
只是一个例子,我的arrays也可能有3列,4列甚至更多。
您正在寻找String#ljust
:
max_cat_size = animals.map(&:first).max_by(&:size).size animals.each do |cat, dog| puts "#{cat.ljust(max_cat_size)} #{dog}" end
如果您想要多个空格,只需在插值中添加相应的量即可。
假设你的arrays是n×m而不是2×m :
animal_max_sizes = animals.first.size.times.map do |index| animals.transpose[index].map(&:to_s).max_by(&:size).size end animals.map do |animal_line| animal_line.each.with_index.reduce('') do |animal_line, (animal, index)| animal_line + animal.to_s.ljust(animal_max_sizes[index].next) end end.each { |animal_line_stringified| puts animal_line_stringified }
注意:如果您的数组包含nil
,数字等,则使用to_s
es。
另一种方法是使用printf样式格式化。 如果您知道每行中总是只有2个单词,那么您可以这样做:
#!/usr/bin/env ruby lines = [ ' cats dogs', ' verrylongcat dog', 'shortcat verrylongdog ', ' cat dog ', ] lines.map(&:strip).each do |line| puts "%-14s%s" % line.split end
输出:
cats dogs verrylongcat dog shortcat verrylongdog cat dog
如果您需要根据数据计算列宽,那么您需要做更多的工作:
# as @ndn showed: first_col_width = lines.map(&:split).map(&:first).max_by(&:size).size + 2 lines.map(&:strip).each do |line| puts "%-#{first_col_width}s%s" % line.split end
这是另一种可变数量列的尝试。 给定这个数组:
animals = [ ['Cats', 'Dogs', 'Fish'], ['Mr. Tinkles', 'Buddy', 'Nemo'], ['Calico', 'Butch', 'Marlin'], ['Ginger', 'Ivy', 'Dory'] ]
我们可以通过transpose
, map
, length
和max
来计算每列的宽度:
widths = animals.transpose.map { |x| x.map(&:length).max } #=> [11, 5, 6]
基于此,我们可以生成一个格式字符串,可以传递给sprintf
(或其快捷方式%
):
row_format = widths.map { |w| "%-#{w}s" }.join(' ') #=> "%-11s %-5s %-6s"
%s
表示字符串参数, 11
和6
是我们的宽度,并且-
左对齐结果。
我们来试试吧:
row_format % animals[0] #=> "Cats Dogs Fish " row_format % animals[1] #=> "Mr. Tinkles Buddy Nemo " row_format % animals[2] #=> "Calico Butch Marlin"
看起来不错,我们应该使用一个循环并将其包装在一个方法中:
def print_table(array) widths = array.transpose.map { |x| x.map(&:length).max } row_format = widths.map { |w| "%-#{w}s" }.join(' ') array.each do |row_values| puts row_format % row_values end end print_table(animals)
输出:
Cats Dogs Fish Mr. Tinkles Buddy Nemo Calico Butch Marlin Ginger Ivy Dory
更复杂的格式
通过一些调整,您还可以输出MySQL样式表:
def print_mysql_table(array) widths = array.transpose.map { |x| x.map(&:length).max } row_format = '|%s|' % widths.map { |w| " %-#{w}s " }.join('|') separator = '+%s+' % widths.map { |w| '-' * (w+2) }.join('+') header, *rows = array puts separator puts row_format % header puts separator rows.each do |row_values| puts row_format % row_values end puts separator end print_mysql_table(animals)
输出:
+-------------+-------+--------+ | Cats | Dogs | Fish | +-------------+-------+--------+ | Mr. Tinkles | Buddy | Nemo | | Calico | Butch | Marlin | | Ginger | Ivy | Dory | +-------------+-------+--------+