从元组列表中创建格式化表格

3

我有一个数据列表,看起来像这样:

[
    (
        1,
        u'python -c \'print("ok")\'',
        u'data',
        u'python'
    ), (
        2,
        u'python -c \'print("this is some data")\'',
        u'data',
        u'python'
    )
]

这些数据是从一个数据库中提取出来并显示的,数据在不断增长。我希望能够将数据以这样的方式进行显示:

Language  |  Type  |   Payload
-------------------------------
 python   |  data  |  python -c 'print("ok")'
 python   |  data  |  python -c 'print("this is some data")'

我有一个函数,有点类似于这个功能,但是它并不完全符合预期:

def print_table(data, cols, width):
    n, r = divmod(len(data), cols)
    pattern = "{{:{}}}".format(width)
    line = "\n".join(pattern * cols for _ in range(n))
    last_line = pattern * r
    print(line.format(*data))
    print(last_line.format(*data[n*cols]))

如何使我的数据输出看起来符合要求?从答案中可以使用 pandas 实现,但我也希望有一种不安装外部模块的方法。

3个回答

2
分析数据的最大宽度并使用字符串格式化 - 之后进行一些“有创意”的格式化:
data = [
    (
        1,
        u'python -c \'print("ok")\'',
        u'data',
        u'python'
    ), (
        2,
        u'python -c \'print("this is some data")\'',
        u'data',
        u'python'
    )
]



def print_table(data):
    widths = {0:0, 3:len("Language"),2:len("Type"),1:len("Payload")}
    for k in data:
        for i,d in enumerate(k): 
            widths[i] = max(widths[i],len(str(d))) 
    # print(widths)

    lan, typ, pay = ["Language","Type","Payload"]
    print(f"{lan:<{widths[3]}}  |  {typ:<{widths[2]}}  |  {pay:<{widths[1]}}")
    # adjust by 10 for '  |  ' twice
    print("-" * (widths[1]+widths[2]+widths[3]+10)) 
    for k in data:
        _, pay, typ, lan = k
        print(f"{lan:<{widths[3]}}  |  {typ:<{widths[2]}}  |  {pay:<{widths[1]}}") 

输出:

Language  |  Type  |  Payload                               
------------------------------------------------------------
python    |  data  |  python -c 'print("ok")'               
python    |  data  |  python -c 'print("this is some data")'

相当于 Python 2.7 代码:

# w == widths - would break 79 chars/line else wise
def print_table(data):
    w = {0:0, 3:len("Language"),2:len("Type"),1:len("Payload")}
    for k in data:
        for i,d in enumerate(k): 
            w[i] = max(w[i],len(str(d))) 


    lan, typ, pay = ["Language","Type","Payload"]
    print "{:<{}}  |  {:<{}}  |  {:<{}}".format(lan, w[3], typ, w[2], pay, w[1])   
    print "-" * (w[1]+w[2]+w[3]+10) 
    for k in data:
        _, pay, typ, lan = k
        print "{:<{}}  |  {:<{}}  |  {:<{}}".format(lan, w[3], typ, w[2], pay, w[1]) 

有没有一种方法可以同时兼容2.x和3+,并且不支持f""的2.x? - 13aal
1
@13aal,你可以将 f'strings' 转换为普通的 .format() 语法 - 参见编辑 - 对于没有看到 Python 2.7 标签感到抱歉 - Python2 不使用 print() 作为函数 - 因此这种方式不兼容 - 你可能需要从 future 中导入 print:如何使用 from-future-import-print-function - Patrick Artner

2
处理任意列数的解决方案:
from operator import itemgetter

data = [
    ('ID', 'Payload', 'Type', 'Language'),
    (1, u'python -c \'print("ok")\'', u'data', u'python'),
    (2, u'python -c \'print("this is some data")\'', u'data', u'python')
]


def print_table(data):
    lengths = [
        [len(str(x)) for x in row]
        for row in data
    ]

    max_lengths = [
        max(map(itemgetter(x), lengths))
        for x in range(0, len(data[0]))
    ]

    format_str = ''.join(map(lambda x: '%%-%ss | ' % x, max_lengths))

    print(format_str % data[0])
    print('-' * (sum(max_lengths) + len(max_lengths) * 3 - 1))

    for x in data[1:]:
        print(format_str % x)

print_table(data)

输出:

$ python table.py
ID | Payload                                | Type | Language |
---------------------------------------------------------------
1  | python -c 'print("ok")'                | data | python   |
2  | python -c 'print("this is some data")' | data | python   |

1
你可以使用 pandas 来实现这个功能:
import pandas as pd
data = pd.DataFrame(a, columns=['id','Payload', 'type', 'Language'])
print(data)

gives you:

   id                                 Payload  type Language
0   1                 python -c 'print("ok")'  data   python
1   2  python -c 'print("this is some data")'  data   python

有没有一种方法可以在不安装其他库的情况下完成它? - 13aal
对不起,我一开始应该说的。 - 13aal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接