在python中创建漂亮的列输出
我正在尝试用python创建一个很好的列列表,用于我创建的命令行管理工具 基本上,我想要一个如下列表:在python中创建漂亮的列输出,python,string,list,Python,String,List,我正在尝试用python创建一个很好的列列表,用于我创建的命令行管理工具 基本上,我想要一个如下列表: [['a', 'b', 'c'], ['aaaaaaaaaa', 'b', 'c'], ['a', 'bbbbbbbbbb', 'c']] 变成: a b c aaaaaaaaaa b c a bbbbbbbbbb c 在这里,使用普通制表符是行不通的,因为我不知道每行中最长的数据 这与Linu
[['a', 'b', 'c'], ['aaaaaaaaaa', 'b', 'c'], ['a', 'bbbbbbbbbb', 'c']]
变成:
a b c
aaaaaaaaaa b c
a bbbbbbbbbb c
在这里,使用普通制表符是行不通的,因为我不知道每行中最长的数据
这与Linux中的“column-t”行为相同
$ echo -e "a b c\naaaaaaaaaa b c\na bbbbbbbbbb c"
a b c
aaaaaaaaaa b c
a bbbbbbbbbb c
$ echo -e "a b c\naaaaaaaaaa b c\na bbbbbbbbbb c" | column -t
a b c
aaaaaaaaaa b c
a bbbbbbbbbb c
我到处寻找各种python库来实现这一点,但找不到任何有用的东西 您必须通过两次传球来完成此操作:
str.ljust()
和str.rjust()
这样做的目的是计算最长的数据项以确定列宽,然后在打印每列时使用
.ljust()
添加必要的填充。像这样变换列是zip的工作:
>>> a = [['a', 'b', 'c'], ['aaaaaaaaaa', 'b', 'c'], ['a', 'bbbbbbbbbb', 'c']]
>>> list(zip(*a))
[('a', 'aaaaaaaaaa', 'a'), ('b', 'b', 'bbbbbbbbbb'), ('c', 'c', 'c')]
要查找每列所需的长度,可以使用max
:
>>> trans_a = zip(*a)
>>> [max(len(c) for c in b) for b in trans_a]
[10, 10, 1]
通过适当的填充,您可以使用它来构造要传递给打印的字符串:
>>> col_lenghts = [max(len(c) for c in b) for b in trans_a]
>>> padding = ' ' # You might want more
>>> padding.join(s.ljust(l) for s,l in zip(a[0], col_lenghts))
'a b c'
自Python 2.6+以来,您可以通过以下方式使用a将列设置为至少20个字符,并将文本向右对齐
table_data = [
['a', 'b', 'c'],
['aaaaaaaaaa', 'b', 'c'],
['a', 'bbbbbbbbbb', 'c']
]
for row in table_data:
print("{: >20} {: >20} {: >20}".format(*row))
输出:
a b c
aaaaaaaaaa b c
a bbbbbbbbbb c
我是带着同样的要求来到这里的,但@lvc和@Preet的答案似乎更符合列-t
产生的结果,因为列的宽度不同:
>>> rows = [ ['a', 'b', 'c', 'd']
... , ['aaaaaaaaaa', 'b', 'c', 'd']
... , ['a', 'bbbbbbbbbb', 'c', 'd']
... ]
...
为了得到更漂亮的桌子,比如
---------------------------------------------------
| First Name | Last Name | Age | Position |
---------------------------------------------------
| John | Smith | 24 | Software |
| | | | Engineer |
---------------------------------------------------
| Mary | Brohowski | 23 | Sales |
| | | | Manager |
---------------------------------------------------
| Aristidis | Papageorgopoulos | 28 | Senior |
| | | | Reseacher |
---------------------------------------------------
您可以使用以下选项:
包含一些改进。基于创建数据帧的解决方案:
import pandas as pd
l = [['a', 'b', 'c'], ['aaaaaaaaaa', 'b', 'c'], ['a', 'bbbbbbbbbb', 'c']]
df = pd.DataFrame(l)
print(df)
0 1 2
0 a b c
1 aaaaaaaaaa b c
2 a bbbbbbbbbb c
for index, row in clipped.iterrows():
rdName = self.colorize(row['name1'],"\033[32m")
rdClass = self.colorize(row['roadClassification'],"\033[93m")
rdFunction = self.colorize(row['roadFunction'],"\033[33m")
rdForm = self.colorize(row['formOfWay'],"\033[94m")
rdLength = self.colorize(row['length'],"\033[97m")
rdDistance = self.colorize(row['distance'],"\033[96m")
print('{0:<30} {1:>35} {2:>35} {3:>35} {4:>20} {5:>20}'.format(rdName,rdClass,rdFunction,rdForm,rdLength,rdDistance) )
要删除索引和标题值以创建所需的输出,可以使用以下方法:
我意识到这个问题很老,但我不理解Antak的答案,也不想使用库,所以我推出了自己的解决方案
解决方案假设记录是二维数组,记录的长度都相同,字段都是字符串
def stringifyRecords(records):
column_widths = [0] * len(records[0])
for record in records:
for i, field in enumerate(record):
width = len(field)
if width > column_widths[i]: column_widths[i] = width
s = ""
for record in records:
for column_width, field in zip(column_widths, record):
s += field.ljust(column_width+1)
s += "\n"
return s
我发现这个答案非常有帮助和优雅,最初来自:
输出
A B
C D
first row: a b c
second row: aaaaaaaaaa b c
third row: a bbbbbbbbbb c
first row: a b c
second row: aaaaaaaaaa b c
third row: aaaaaaaaaa b c
下面是肖恩·琴回答的一个变体。每列的宽度是固定的,而不是所有列的宽度。在第一行下方和列之间还有一个边框。(库用于强制执行合同。)
以下是一个例子:
>>> table = [['column 0', 'another column 1'], ['00', '01'], ['10', '11']]
>>> result = packagery._format_table(table=table)
>>> print(result)
column 0 | another column 1
---------+-----------------
00 | 01
10 | 11
这是一个有点晚的聚会,一个无耻的插件为一个包我写的,但你也可以检查包
它接受输入列表和标题列表,并输出一个表格式的字符串。此代码段创建一个docker样式的表:
从columnar导入columnar
headers=['name','id','host','notes']
数据=[
['busybox'、'c3c37d5d-38d2-409f-8d02-600fd9d51239'、'linuxnode-1-292735'、'测试服务器',
['alpine-python'、'6bb77855-0fda-45a9-b553-e19e1a795f1e'、'linuxnode-2-249253'、'运行python的那个',
['redis'、'afb648ba-ac97-4fb2-8953-9a5b5f39663e'、'linuxnode-3-3416918'、'用于队列和其他东西',
[“应用程序服务器”、“b866cd0f-bf80-40c7-84e3-c40891ec68f9”、“linuxnode-4-295918”、“热门目的地”。],
['nginx','76fea0f0-aa53-4911-b7e4-fae28c2e469b','linuxnode-5-292735','Traffic Cop'],
]
表=列(数据、标题、无边框=真)
打印(表格)
或者你可以找一个有颜色和边框的小爱好者。
要阅读有关列大小调整算法的更多信息并查看API的其余部分,您可以查看上面的链接或查看是一个新的库,它允许您在自动调整列宽的同时轻松打印流式列数据
(免责声明:我是作者)更新了@Franck Dernoncourt fancy配方,使其符合python 3和PEP8
import io
import math
import operator
import re
import functools
from itertools import zip_longest
def indent(
rows,
has_header=False,
header_char="-",
delim=" | ",
justify="left",
separate_rows=False,
prefix="",
postfix="",
wrapfunc=lambda x: x,
):
"""Indents a table by column.
- rows: A sequence of sequences of items, one sequence per row.
- hasHeader: True if the first row consists of the columns' names.
- headerChar: Character to be used for the row separator line
(if hasHeader==True or separateRows==True).
- delim: The column delimiter.
- justify: Determines how are data justified in their column.
Valid values are 'left','right' and 'center'.
- separateRows: True if rows are to be separated by a line
of 'headerChar's.
- prefix: A string prepended to each printed row.
- postfix: A string appended to each printed row.
- wrapfunc: A function f(text) for wrapping text; each element in
the table is first wrapped by this function."""
# closure for breaking logical rows to physical, using wrapfunc
def row_wrapper(row):
new_rows = [wrapfunc(item).split("\n") for item in row]
return [[substr or "" for substr in item] for item in zip_longest(*new_rows)]
# break each logical row into one or more physical ones
logical_rows = [row_wrapper(row) for row in rows]
# columns of physical rows
columns = zip_longest(*functools.reduce(operator.add, logical_rows))
# get the maximum of each column by the string length of its items
max_widths = [max([len(str(item)) for item in column]) for column in columns]
row_separator = header_char * (
len(prefix) + len(postfix) + sum(max_widths) + len(delim) * (len(max_widths) - 1)
)
# select the appropriate justify method
justify = {"center": str.center, "right": str.rjust, "left": str.ljust}[
justify.lower()
]
output = io.StringIO()
if separate_rows:
print(output, row_separator)
for physicalRows in logical_rows:
for row in physicalRows:
print( output, prefix + delim.join(
[justify(str(item), width) for (item, width) in zip(row, max_widths)]
) + postfix)
if separate_rows or has_header:
print(output, row_separator)
has_header = False
return output.getvalue()
# written by Mike Brown
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/148061
def wrap_onspace(text, width):
"""
A word-wrap function that preserves existing line breaks
and most spaces in the text. Expects that existing line
breaks are posix newlines (\n).
"""
return functools.reduce(
lambda line, word, i_width=width: "%s%s%s"
% (
line,
" \n"[
(
len(line[line.rfind("\n") + 1 :]) + len(word.split("\n", 1)[0])
>= i_width
)
],
word,
),
text.split(" "),
)
def wrap_onspace_strict(text, i_width):
"""Similar to wrap_onspace, but enforces the width constraint:
words longer than width are split."""
word_regex = re.compile(r"\S{" + str(i_width) + r",}")
return wrap_onspace(
word_regex.sub(lambda m: wrap_always(m.group(), i_width), text), i_width
)
def wrap_always(text, width):
"""A simple word-wrap function that wraps text on exactly width characters.
It doesn't split the text in words."""
return "\n".join(
[
text[width * i : width * (i + 1)]
for i in range(int(math.ceil(1.0 * len(text) / width)))
]
)
if __name__ == "__main__":
labels = ("First Name", "Last Name", "Age", "Position")
data = """John,Smith,24,Software Engineer
Mary,Brohowski,23,Sales Manager
Aristidis,Papageorgopoulos,28,Senior Reseacher"""
rows = [row.strip().split(",") for row in data.splitlines()]
print("Without wrapping function\n")
print(indent([labels] + rows, has_header=True))
# test indent with different wrapping functions
width = 10
for wrapper in (wrap_always, wrap_onspace, wrap_onspace_strict):
print("Wrapping function: %s(x,width=%d)\n" % (wrapper.__name__, width))
print(
indent(
[labels] + rows,
has_header=True,
separate_rows=True,
prefix="| ",
postfix=" |",
wrapfunc=lambda x: wrapper(x, width),
)
)
# output:
#
# Without wrapping function
#
# First Name | Last Name | Age | Position
# -------------------------------------------------------
# John | Smith | 24 | Software Engineer
# Mary | Brohowski | 23 | Sales Manager
# Aristidis | Papageorgopoulos | 28 | Senior Reseacher
#
# Wrapping function: wrap_always(x,width=10)
#
# ----------------------------------------------
# | First Name | Last Name | Age | Position |
# ----------------------------------------------
# | John | Smith | 24 | Software E |
# | | | | ngineer |
# ----------------------------------------------
# | Mary | Brohowski | 23 | Sales Mana |
# | | | | ger |
# ----------------------------------------------
# | Aristidis | Papageorgo | 28 | Senior Res |
# | | poulos | | eacher |
# ----------------------------------------------
#
# Wrapping function: wrap_onspace(x,width=10)
#
# ---------------------------------------------------
# | First Name | Last Name | Age | Position |
# ---------------------------------------------------
# | John | Smith | 24 | Software |
# | | | | Engineer |
# ---------------------------------------------------
# | Mary | Brohowski | 23 | Sales |
# | | | | Manager |
# ---------------------------------------------------
# | Aristidis | Papageorgopoulos | 28 | Senior |
# | | | | Reseacher |
# ---------------------------------------------------
#
# Wrapping function: wrap_onspace_strict(x,width=10)
#
# ---------------------------------------------
# | First Name | Last Name | Age | Position |
# ---------------------------------------------
# | John | Smith | 24 | Software |
# | | | | Engineer |
# ---------------------------------------------
# | Mary | Brohowski | 23 | Sales |
# | | | | Manager |
# ---------------------------------------------
# | Aristidis | Papageorgo | 28 | Senior |
# | | poulos | | Reseacher |
# ---------------------------------------------
这将根据其他答案中使用的最大度量设置独立的最佳列宽
data = [['a', 'b', 'c'], ['aaaaaaaaaa', 'b', 'c'], ['a', 'bbbbbbbbbb', 'c']]
padding = 2
col_widths = [max(len(w) for w in [r[cn] for r in data]) + padding for cn in range(len(data[0]))]
format_string = "{{:{}}}{{:{}}}{{:{}}}".format(*col_widths)
for row in data:
print(format_string.format(*row))
懒惰的人
正在使用Python 3.*和熊猫/Geopandas的;通用简单类内方法(对于“普通”脚本,只需删除self):
函数着色:
def colorize(self,s,color):
s = color+str(s)+"\033[0m"
return s
print('{0:<23} {1:>24} {2:>26} {3:>26} {4:>11} {5:>11}'.format('Road name','Classification','Function','Form of road','Length','Distance') )
标题:
def colorize(self,s,color):
s = color+str(s)+"\033[0m"
return s
print('{0:<23} {1:>24} {2:>26} {3:>26} {4:>11} {5:>11}'.format('Road name','Classification','Function','Form of road','Length','Distance') )
print({0:24}{2:>26}{3:>26}{4:>11}{5:>11})。格式('Road name','Classification','Function','Form of Road','Length','Distance'))
然后是熊猫/Geopandas数据帧中的数据:
import pandas as pd
l = [['a', 'b', 'c'], ['aaaaaaaaaa', 'b', 'c'], ['a', 'bbbbbbbbbb', 'c']]
df = pd.DataFrame(l)
print(df)
0 1 2
0 a b c
1 aaaaaaaaaa b c
2 a bbbbbbbbbb c
for index, row in clipped.iterrows():
rdName = self.colorize(row['name1'],"\033[32m")
rdClass = self.colorize(row['roadClassification'],"\033[93m")
rdFunction = self.colorize(row['roadFunction'],"\033[33m")
rdForm = self.colorize(row['formOfWay'],"\033[94m")
rdLength = self.colorize(row['length'],"\033[97m")
rdDistance = self.colorize(row['distance'],"\033[96m")
print('{0:<30} {1:>35} {2:>35} {3:>35} {4:>20} {5:>20}'.format(rdName,rdClass,rdFunction,rdForm,rdLength,rdDistance) )
对于clipped.iterrows()中的索引行:
rName=self.colorize(行['name1'],“\033[32m”)
rdClass=self.colorize(行['roadClassification'],“\033[93m”)
rdFunction=self.colorize(行['roadFunction'],“\033[33m”)
rdForm=self.colorize(行['formOfWay'],“\033[94m”)
rdLength=self.colorize(行['length'],“\033[97m”)
rdDistance=self.colorize(行['distance'],“\033[96m”)
打印({0:35}{2:>35}{3:>35}{4:>20}{5:>20})。格式(rdName、rdClass、rdFunction、rdForm、rdLength、rdDistance))
代码{0:35}{2:>35}{3:>35}{4:>20}{5:>20}
:
def colorize(self,s,color):
s = color+str(s)+"\033[0m"
return s
print('{0:<23} {1:>24} {2:>26} {3:>26} {4:>11} {5:>11}'.format('Road name','Classification','Function','Form of road','Length','Distance') )
0、1、2、3、4、5列
->本例共有6列
30,35,20
->列的宽度(请注意,您必须添加长度\033[96m
-这对于Python也是一个字符串),只需进行实验:)
,justify:right,left(也有=
用于填充零)
若你们想区分,比如最大值,你们必须切换到特殊的熊猫风格的函数,但假设这足够在终端窗口上显示数据
结果:
与之前的答案略有不同(我没有足够的代表对此进行评论)。格式库允许您指定元素的宽度和对齐方式,但不能指定元素的起始位置,也就是说,您可以说“20列宽”,但不能说“从20列开始”。这导致了此问题:
table_data = [
['a', 'b', 'c'],
['aaaaaaaaaa', 'b', 'c'],
['a', 'bbbbbbbbbb', 'c']
]
print("first row: {: >20} {: >20} {: >20}".format(*table_data[0]))
print("second row: {: >20} {: >20} {: >20}".format(*table_data[1]))
print("third row: {: >20} {: >20} {: >20}".format(*table_data[2]))
输出
A B
C D
first row: a b c
second row: aaaaaaaaaa b c
third row: a bbbbbbbbbb c
first row: a b c
second row: aaaaaaaaaa b c
third row: aaaaaaaaaa b c
当然,答案是格式化文本字符串,这与格式结合起来有点奇怪:
table_data = [
['a', 'b', 'c'],
['aaaaaaaaaa', 'b', 'c'],
['a', 'bbbbbbbbbb', 'c']
]
print(f"{'first row:': <20} {table_data[0][0]: >20} {table_data[0][1]: >20} {table_data[0][2]: >20}")
print("{: <20} {: >20} {: >20} {: >20}".format(*['second row:', *table_data[1]]))
print("{: <20} {: >20} {: >20} {: >20}".format(*['third row:', *table_data[1]]))
您可以准备数据并将其传递给real列
实用程序
让我们假设