【问题标题】:Printing Lists as Tabular Data将列表打印为表格数据
【发布时间】:2012-03-21 02:42:53
【问题描述】:

我对 Python 还是很陌生,现在我正在努力为打印输出格式化我的数据。

我有一个用于两个标题的列表,以及一个应该是表格内容的矩阵。像这样:

teams_list = ["Man Utd", "Man City", "T Hotspur"]
data = np.array([[1, 2, 1],
                 [0, 1, 0],
                 [2, 4, 2]])

请注意,标题名称的长度不一定相同。不过,数据条目都是整数。

现在,我想用表格格式表示它,如下所示:

            Man Utd   Man City   T Hotspur
  Man Utd         1          0           0
 Man City         1          1           0
T Hotspur         0          1           2

我有一种预感,它必须有一个数据结构,但我找不到它。我尝试过使用字典和格式化打印,我尝试过带有缩进的 for 循环,我尝试过打印为字符串。

我确信一定有一个非常简单的方法可以做到这一点,但由于缺乏经验,我可能会错过它。

【问题讨论】:

  • +1,我昨晚只是想做同样的事情。您只是想打印到命令行还是使用 GUI 模块?
  • 只是打印到命令行。但是,它需要通过一个单元测试用例,所以格式化在这里非常重要。
  • 请注意,这里的要求非常专业,因为行和列标签是相同的。因此,对于这种特殊情况,即席代码是一个很好的例子,说明这很容易。但是这里的其他解决方案可能更适合更通用的表格显示。

标签: python


【解决方案1】:

为此目的有一些轻巧有用的python包:

1.制表https://pypi.python.org/pypi/tabulate

from tabulate import tabulate
print(tabulate([['Alice', 24], ['Bob', 19]], headers=['Name', 'Age']))
Name      Age
------  -----
Alice      24
Bob        19

tabulate 有许多选项来指定标题和表格格式。

print(tabulate([['Alice', 24], ['Bob', 19]], headers=['Name', 'Age'], tablefmt='orgtbl'))
| Name   |   Age |
|--------+-------|
| Alice  |    24 |
| Bob    |    19 |

2。 PrettyTable:https://pypi.python.org/pypi/PrettyTable

from prettytable import PrettyTable
t = PrettyTable(['Name', 'Age'])
t.add_row(['Alice', 24])
t.add_row(['Bob', 19])
print(t)
+-------+-----+
|  Name | Age |
+-------+-----+
| Alice |  24 |
|  Bob  |  19 |
+-------+-----+

PrettyTable 具有从 csv、html、sql 数据库读取数据的选项。您还可以选择数据子集、对表格进行排序和更改表格样式。

3.文本表https://pypi.python.org/pypi/texttable

from texttable import Texttable
t = Texttable()
t.add_rows([['Name', 'Age'], ['Alice', 24], ['Bob', 19]])
print(t.draw())
+-------+-----+
| Name  | Age |
+=======+=====+
| Alice | 24  |
+-------+-----+
| Bob   | 19  |
+-------+-----+

使用 texttable,您可以控制水平/垂直对齐、边框样式和数据类型。

4.术语表https://github.com/nschloe/termtables

import termtables as tt

string = tt.to_string(
    [["Alice", 24], ["Bob", 19]],
    header=["Name", "Age"],
    style=tt.styles.ascii_thin_double,
    # alignment="ll",
    # padding=(0, 1),
)
print(string)
+-------+-----+
| Name  | Age |
+=======+=====+
| Alice | 24  |
+-------+-----+
| Bob   | 19  |
+-------+-----+

使用 texttable,您可以控制水平/垂直对齐、边框样式和数据类型。

其他选项:

  • terminaltables 从字符串列表轻松地在终端/控制台应用程序中绘制表格。支持多行。
  • asciitable Asciitable 可以通过内置的扩展阅读器类读写各种 ASCII 表格格式。

【讨论】:

  • 我发现制表是构建以数据为中心的 CLI 工具的非常有用的工具。再加上点击(pip install click),你就可以大吃一惊了。
  • 这太棒了,谢谢。就个人而言,您更喜欢这三个中的哪一个?
  • 精彩的回复! PrettyTable 真是太好了 - 其他两个选项之间的完美平衡。
  • 终端表适合中文,可能其他非英语语言
  • 我刚刚玩过主要的包和 IMO “beautifultable” - 最好的、维护的、良好的 API 和 doco,支持彩色。 “texttable” - 不错的、维护良好的 API,但使用彩色会导致表格不对齐。 “终端表” - 很好,仅通过代码示例进行 doco。 “PrettyTable” - 好的,但是旧的表“标题”对我不起作用。 “制表” - 不错,但官方 pypi 版本不支持列对齐 coalign 关键字。 “tableprint” - 平均,API 复杂,没有足够的常见用法示例。
【解决方案2】:

一些临时代码:

row_format ="{:>15}" * (len(teams_list) + 1)
print(row_format.format("", *teams_list))
for team, row in zip(teams_list, data):
    print(row_format.format(team, *row))

这依赖于str.format()Format Specification Mini-Language

【讨论】:

  • 如果正文中的数据大于表头,可以根据第一行数据设置列宽。 for t in data[0]: row_format+="{:
  • 我喜欢这个解决方案胜过接受一个,因为它不需要第三方库。想要添加另一个方便的技巧:您可以使用字符串的最大长度作为列的宽度,而不是硬编码的数字。它将是这样的:f'{team:>{max_len_of_team}}'。
【解决方案3】:
>>> import pandas
>>> pandas.DataFrame(data, teams_list, teams_list)
           Man Utd  Man City  T Hotspur
Man Utd    1        2         1        
Man City   0        1         0        
T Hotspur  2        4         2        

【讨论】:

  • 这看起来很有希望,谢谢,但我试图做到这一点,而不使用任何超过绝对必要的导入库。
  • 仅将 pandas 用于输出格式似乎有点矫枉过正(大写 O)。
  • @NielsBom:为输出格式化而来,为数据分析和建模留下:)
  • @J.F.Sebastian 对我来说更像是“为输出格式而来,尖叫着逃跑,因为 10 分钟的 numpy 编译让我的电脑听起来像吹风机”;-)
  • @NielsBom:pip install numpy uses binary wheels now on most platforms (no compilation)。显然,其他二进制安装选项甚至在此之前就可用。
【解决方案4】:

Python 实际上让这很容易。

类似

for i in range(10):
    print '%-12i%-12i' % (10 ** i, 20 ** i)

会有输出

1           1           
10          20          
100         400         
1000        8000        
10000       160000      
100000      3200000     
1000000     64000000    
10000000    1280000000  
100000000   25600000000
1000000000  512000000000

字符串中的 % 本质上是一个转义字符,它后面的字符告诉 python 数据应该有什么样的格式。字符串外面和后面的 % 告诉python你打算使用前面的字符串作为格式字符串,后面的数据应该按照指定的格式放入。

在这种情况下,我使用了两次“%-12i”。分解每个部分:

'-' (left align)
'12' (how much space to be given to this part of the output)
'i' (we are printing an integer)

来自文档:https://docs.python.org/2/library/stdtypes.html#string-formatting

【讨论】:

  • 这个答案让我找到了我想要的东西!对于 python 3,我最终像 print('%-20.2f' % position['deg'], '%-17.2f' % position['v2']) 一样使用它,其中 .2 指定浮点精度 f
  • 打印整数时我会右对齐,但我猜这是个人喜好。
【解决方案5】:

更新 Sven Marnach 在 Python 3.4 中工作的答案:

row_format ="{:>15}" * (len(teams_list) + 1)
print(row_format.format("", *teams_list))
for team, row in zip(teams_list, data):
    print(row_format.format(team, *row))

【讨论】:

    【解决方案6】:

    我知道我参加聚会迟到了,但我只是为此创建了一个库,我认为这真的可以提供帮助。它非常简单,这就是我认为你应该使用它的原因。它被称为 TableIT

    基本使用

    要使用它,请先按照GitHub Page上的下载说明进行操作。

    然后导入:

    import TableIt
    

    然后制作一个列表列表,其中每个内部列表都是一行:

    table = [
        [4, 3, "Hi"],
        [2, 1, 808890312093],
        [5, "Hi", "Bye"]
    ]
    

    那么你所要做的就是打印它:

    TableIt.printTable(table)
    

    这是你得到的输出:

    +--------------------------------------------+
    | 4            | 3            | Hi           |
    | 2            | 1            | 808890312093 |
    | 5            | Hi           | Bye          |
    +--------------------------------------------+
    

    字段名称

    如果您愿意,可以使用字段名称(如果您不使用字段名称,则不必说 useFieldNames=False,因为它默认设置为 ): p>

    
    TableIt.printTable(table, useFieldNames=True)
    

    从中你会得到:

    +--------------------------------------------+
    | 4            | 3            | Hi           |
    +--------------+--------------+--------------+
    | 2            | 1            | 808890312093 |
    | 5            | Hi           | Bye          |
    +--------------------------------------------+
    

    还有其他用途,例如您可以这样做:

    import TableIt
    
    myList = [
        ["Name", "Email"],
        ["Richard", "richard@fakeemail.com"],
        ["Tasha", "tash@fakeemail.com"]
    ]
    
    TableIt.print(myList, useFieldNames=True)
    

    由此而来:

    +-----------------------------------------------+
    | Name                  | Email                 |
    +-----------------------+-----------------------+
    | Richard               | richard@fakeemail.com |
    | Tasha                 | tash@fakeemail.com    |
    +-----------------------------------------------+
    

    或者你可以这样做:

    import TableIt
    
    myList = [
        ["", "a", "b"],
        ["x", "a + x", "a + b"],
        ["z", "a + z", "z + b"]
    ]
    
    TableIt.printTable(myList, useFieldNames=True)
    

    然后你会得到:

    +-----------------------+
    |       | a     | b     |
    +-------+-------+-------+
    | x     | a + x | a + b |
    | z     | a + z | z + b |
    +-----------------------+
    

    颜色

    你也可以使用颜色。

    您可以通过使用颜色选项(默认设置为无)并指定 RGB 值来使用颜色。

    使用上面的例子:

    import TableIt
    
    myList = [
        ["", "a", "b"],
        ["x", "a + x", "a + b"],
        ["z", "a + z", "z + b"]
    ]
    
    TableIt.printTable(myList, useFieldNames=True, color=(26, 156, 171))
    

    然后你会得到:

    请注意,打印颜色可能不适合您,但它的工作方式与打印彩色文本的其他库完全相同。我已经测试过,每种颜色都有效。蓝色也不会像使用默认的34m ANSI 转义序列那样搞砸(如果你不知道那是什么也没关系)。无论如何,这一切都源于每个颜色都是 RGB 值而不是系统默认值。

    更多信息

    更多信息请查看GitHub Page

    【讨论】:

    • Table 真是个不错的工具。简单但功能强大。我认为唯一的缺点是 TableIt 没有声明一个许可证
    • @Endle_Zhenbo 嘿!非常感谢,我会尽快处理的!
    • @Endle_Zhenbo,我知道已经有一段时间了,但我终于在项目上放了许可证。
    • 关于何时可以安装 pip 的任何更新?
    • @pasha 我会在下周发布它,不过我的目标是明天!
    【解决方案7】:

    随便用吧

    from beautifultable import BeautifulTable
    
    table = BeautifulTable()
    table.column_headers = ["", "Man Utd","Man City","T Hotspur"]
    table.append_row(['Man Utd',  1,  2,  3])
    table.append_row(['Man City', 7, 4,  1])
    table.append_row(['T Hotspur', 3, 2,  2])
    print(table)
    

    因此,您将得到一张如此整洁的桌子,仅此而已。

    【讨论】:

    【解决方案8】:

    当我这样做时,我喜欢对表格格式的细节进行一些控制。特别是,我希望标题单元格具有与正文单元格不同的格式,并且表格列宽仅与每个单元格一样宽。这是我的解决方案:

    def format_matrix(header, matrix,
                      top_format, left_format, cell_format, row_delim, col_delim):
        table = [[''] + header] + [[name] + row for name, row in zip(header, matrix)]
        table_format = [['{:^{}}'] + len(header) * [top_format]] \
                     + len(matrix) * [[left_format] + len(header) * [cell_format]]
        col_widths = [max(
                          len(format.format(cell, 0))
                          for format, cell in zip(col_format, col))
                      for col_format, col in zip(zip(*table_format), zip(*table))]
        return row_delim.join(
                   col_delim.join(
                       format.format(cell, width)
                       for format, cell, width in zip(row_format, row, col_widths))
                   for row_format, row in zip(table_format, table))
    
    print format_matrix(['Man Utd', 'Man City', 'T Hotspur', 'Really Long Column'],
                        [[1, 2, 1, -1], [0, 1, 0, 5], [2, 4, 2, 2], [0, 1, 0, 6]],
                        '{:^{}}', '{:<{}}', '{:>{}.3f}', '\n', ' | ')
    

    这是输出:

                       | Man Utd | Man City | T Hotspur | Really Long Column
    Man Utd            |   1.000 |    2.000 |     1.000 |             -1.000
    Man City           |   0.000 |    1.000 |     0.000 |              5.000
    T Hotspur          |   2.000 |    4.000 |     2.000 |              2.000
    Really Long Column |   0.000 |    1.000 |     0.000 |              6.000
    

    【讨论】:

      【解决方案9】:

      执行此操作的一种简单方法是遍历所有列,测量它们的宽度,为该最大宽度创建一个 row_template,然后打印行。 这不是您要查找的内容,因为在这种情况下,您首先必须将标题放入表格中,但我认为它可能对某人有用否则。

      table = [
          ["", "Man Utd", "Man City", "T Hotspur"],
          ["Man Utd", 1, 0, 0],
          ["Man City", 1, 1, 0],
          ["T Hotspur", 0, 1, 2],
      ]
      def print_table(table):
          longest_cols = [
              (max([len(str(row[i])) for row in table]) + 3)
              for i in range(len(table[0]))
          ]
          row_format = "".join(["{:>" + str(longest_col) + "}" for longest_col in longest_cols])
          for row in table:
              print(row_format.format(*row))
      

      你可以这样使用它:

      >>> print_table(table)
      
                  Man Utd   Man City   T Hotspur
        Man Utd         1          0           0
       Man City         1          1           0
      T Hotspur         0          1           2
      

      【讨论】:

      • 很好,为了最小化我们可以使用 zip(*matrix) 来获取 cols。所以要在 col 中获得 max len:[len(max(col , key=len))+3 for col in zip(*table)]。我尝试将.format and f-string 与可变填充填充一起使用,并在f-string 初始化后使用eval 在稍后的时间点应用pad len。但没有成功,最终使用了这种方法。
      • @Rilwan:你确定我们需要最小化吗?我对上面的可读性感到非常满意,尤其是因为我是 3 年前写的,现在我仍然理解它的作用。
      • 不一定,只是我们的选择。由于我们有内置的 zipper 合并实用程序可用,我倾向于使用 zip(*matrix) 来获取列值,而不是遍历行并通过索引获取值。于是想到分享。谢谢。
      【解决方案10】:

      我认为this 是您正在寻找的。​​p>

      这是一个简单的模块,它只计算表格条目所需的最大宽度,然后只使用rjustljust 对数据进行漂亮的打印。

      如果您希望左标题右对齐,只需更改此调用:

       print >> out, row[0].ljust(col_paddings[0] + 1),
      

      从第 53 行开始:

       print >> out, row[0].rjust(col_paddings[0] + 1),
      

      【讨论】:

      • 链接好像失效了。你有更新的链接吗?
      【解决方案11】:

      纯 Python 3

      def print_table(data, cols, wide):
          '''Prints formatted data on columns of given width.'''
          n, r = divmod(len(data), cols)
          pat = '{{:{}}}'.format(wide)
          line = '\n'.join(pat * cols for _ in range(n))
          last_line = pat * r
          print(line.format(*data))
          print(last_line.format(*data[n*cols:]))
      
      data = [str(i) for i in range(27)]
      print_table(data, 6, 12)
      

      将打印

      0           1           2           3           4           5           
      6           7           8           9           10          11          
      12          13          14          15          16          17          
      18          19          20          21          22          23          
      24          25          26
      

      【讨论】:

        【解决方案12】:

        对于简单的情况,您可以只使用现代字符串格式 (simplified Sven's answer):
        f'{column1_value:15} {column2_value}':

        table = {
            'Amplitude': [round(amplitude, 3), 'm³/h'],
            'MAE': [round(mae, 2), 'm³/h'],
            'MAPE': [round(mape, 2), '%'],
        }
        
        for metric, value in table.items():
            print(f'{metric:14} : {value[0]:>6.3f} {value[1]}')
        

        输出:

        Amplitude      :  1.438 m³/h
        MAE            :  0.171 m³/h
        MAPE           : 27.740 %
        

        来源:https://docs.python.org/3/tutorial/inputoutput.html#formatted-string-literals

        【讨论】:

          【解决方案13】:

          以下函数将使用 Python 3(也可能是 Python 2)创建请求的表(有或没有 numpy)。我选择设置每列的宽度以匹配最长的团队名称。如果您想为每列使用团队名称的长度,您可以修改它,但会更复杂。

          注意:对于 Python 2 中的直接等效项,您可以将 zip 替换为 itertools 中的 izip

          def print_results_table(data, teams_list):
              str_l = max(len(t) for t in teams_list)
              print(" ".join(['{:>{length}s}'.format(t, length = str_l) for t in [" "] + teams_list]))
              for t, row in zip(teams_list, data):
                  print(" ".join(['{:>{length}s}'.format(str(x), length = str_l) for x in [t] + row]))
          
          teams_list = ["Man Utd", "Man City", "T Hotspur"]
          data = [[1, 2, 1],
                  [0, 1, 0],
                  [2, 4, 2]]
          
          print_results_table(data, teams_list)
          

          这将产生下表:

                      Man Utd  Man City T Hotspur
            Man Utd         1         2         1
           Man City         0         1         0
          T Hotspur         2         4         2
          

          如果你想有垂直的行分隔符,你可以用" | ".join替换" ".join

          参考资料:

          【讨论】:

            【解决方案14】:

            我会尝试遍历列表并使用 CSV 格式化程序来表示您想要的数据。

            您可以指定制表符、逗号或任何其他字符作为分隔符。

            否则,只需遍历列表并在每个元素后打印“\t”

            http://docs.python.org/library/csv.html

            【讨论】:

            • 这是我最初的尝试,大概可以做到,但要让格式完美,似乎需要付出很多努力。
            【解决方案15】:

            我发现这只是在寻找一种输出简单列的方法。 如果您只需要简单的列,那么您可以使用这个:

            print("Titlex\tTitley\tTitlez")
            for x, y, z in data:
                print(x, "\t", y, "\t", z)
            

            编辑:我试图尽可能简单,因此手动做了一些事情,而不是使用团队列表。概括为 OP 的实际问题:

            #Column headers
            print("", end="\t")
            for team in teams_list:
                print(" ", team, end="")
            print()
            # rows
            for team, row in enumerate(data):
                teamlabel = teams_list[team]
                while len(teamlabel) < 9:
                    teamlabel = " " + teamlabel
                print(teamlabel, end="\t")
                for entry in row:
                    print(entry, end="\t")
                print()
            

            输出:

                      Man Utd  Man City  T Hotspur
              Man Utd       1       2       1   
             Man City       0       1       0   
            T Hotspur       2       4       2   
            

            但这似乎不再比其他答案更简单,也许它的好处是它不需要更多的导入。但是@campkeith 的答案已经满足了这一点,并且更强大,因为它可以处理更广泛的标签长度​​。

            【讨论】:

            【解决方案16】:

            我有一个更好的,可以节省很多空间。

            table = [
                ['number1', 'x', 'name'],
                ["4x", "3", "Hi"],
                ["2", "1", "808890312093"],
                ["5", "Hi", "Bye"]
            ]
            column_max_width = [max(len(row[column_index]) for row in table) for column_index in range(len(table[0]))]
            row_format = ["{:>"+str(width)+"}" for width in column_max_width]
            for row in table:
                print("|".join([print_format.format(value) for print_format, value in zip(row_format, row)]))
            

            输出:

            number1| x|        name
                 4x| 3|          Hi
                  2| 1|808890312093
                  5|Hi|         Bye
            

            【讨论】:

              【解决方案17】:

              要使用terminaltables 创建一个简单表,请打开终端或命令提示符并运行pip install terminaltables

              您可以按如下方式打印 Python 列表:

              from terminaltables import AsciiTable
              
              l = [
                ['Head', 'Head'],
                ['R1 C1', 'R1 C2'],
                ['R2 C1', 'R2 C2'],
                ['R3 C1', 'R3 C2']
              ]
              
              table = AsciiTable(l)
              print(table.table)
              

              【讨论】:

                【解决方案18】:
                table_data= [[1,2,3],[4,5,6],[7,8,9]]
                
                for row in table_data:
                    print("{: >20} {: >20} {: >20}".format(*row))
                

                输出:

                               1                  2                3
                               4                  5                6
                               7                  8                9
                

                其中 f 字符串格式化

                1. ">" 用于右对齐

                20为空间宽度,可根据需要改变。

                【讨论】:

                • 介意详细说明 ">20" 在这里是什么意思吗?
                • @AlexanderSantos Just f 字符串格式化文本右对齐的方式(20 是为右对齐保留的空间宽度 & > 用于右对齐 / geeksforgeeks.org/string-alignment-in-python-f-string 2.stackabuse.com/formatting-strings-with-python
                【解决方案19】:

                尝试致富:https://github.com/Textualize/rich

                from rich.console import Console
                from rich.table import Table
                
                console = Console()
                
                table = Table(show_header=True, header_style="bold magenta")
                table.add_column("Date", style="dim", width=12)
                table.add_column("Title")
                table.add_column("Production Budget", justify="right")
                table.add_column("Box Office", justify="right")
                table.add_row(
                    "Dec 20, 2019", "Star Wars: The Rise of Skywalker", "$275,000,000", "$375,126,118"
                )
                table.add_row(
                    "May 25, 2018",
                    "[red]Solo[/red]: A Star Wars Story",
                    "$275,000,000",
                    "$393,151,347",
                )
                table.add_row(
                    "Dec 15, 2017",
                    "Star Wars Ep. VIII: The Last Jedi",
                    "$262,000,000",
                    "[bold]$1,332,539,889[/bold]",
                )
                
                console.print(table)
                

                https://github.com/willmcgugan/rich/raw/master/imgs/table.png

                【讨论】:

                • 我在 termtables 答案中找到了这个链接,如果还没有,我会在这里添加它。我喜欢它的是我可以设置一行的样式,让选定行的颜色反转,它可以混合样式。如果我的所有列都具有特定颜色,并且我选择的行 bg/fg 颜色反转,它会在每个单元格中应用这两种样式。
                猜你喜欢
                • 2015-11-06
                • 2019-08-24
                • 2019-09-19
                • 2014-10-13
                • 1970-01-01
                • 1970-01-01
                • 2018-03-09
                • 2016-01-26
                相关资源
                最近更新 更多