【问题标题】:How to print a 2D array with fixed column width如何打印具有固定列宽的二维数组
【发布时间】:2016-05-09 18:08:04
【问题描述】:

我有一个数组:

animals = [
  ["cats", "dogs"],
  ["verrylongcat", "dog"],
  ["shortcat", "verrylongdog"],
  ["cat", "dog"]
]

我想很好地展示它。有没有一种简单的方法可以使列的宽度固定,所以我得到这样的东西:

cats            dogs
verrylongcat    dog
shortcat        verrylongdog
cat             dog

animals 只是一个例子,我的数组也可以有 3、4 列甚至更多。

【问题讨论】:

  • 请说明输入数组是什么。它是一个文本行数组,还是一个包含 2 个字符串(单词)的数组?
  • 为什么急于选择答案?

标签: arrays ruby printing 2d


【解决方案1】:

您正在寻找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

如果您想要多个空格,只需在插值中添加相应的数量即可。


假设您的数组是 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 }

注意:如果您的数组包含nils、数字等,则使用to_ses。

【讨论】:

  • 但是如果我的数组有 3 或 4 列甚至更多呢? :)
  • 那么你不要像猫狗那样做任何假设,你把你的输入数据当作一个可变大小数组的数组。您不仅要扫描数据的最大大小,还要扫描最大字数(列)以及这些列字的 每个 的最大宽度。
  • 所以没有更简单、更易读的方法吗? :p 该死的
  • @ndn 非常感谢
  • @nbn 我只是复制粘贴了您的代码,它可以工作,但由于某种原因,我得到了两次表! :P
【解决方案2】:

另一种方法是使用 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

【讨论】:

    【解决方案3】:

    这是对可变列数的另一种尝试。给定这个数组:

    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、5 和 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   |
    +-------------+-------+--------+
    

    【讨论】:

    • 不错,即使您继续沿着这条路走,您也不妨使用dedicated gem。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-26
    • 1970-01-01
    • 2011-03-02
    • 2020-11-17
    • 2018-07-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多