以整洁的方式打印列表 Columns/Table
Print List of Lists in Neat Columns/Table
我有一个结构为 [[s: str, s: str, s: str]]
的列表列表,其中可以有任意数量的项目(列表)。
我想像这样在列中干净地打印它:
FirstFirst FirstSecond FirstThird
SecondFirst SecondSecond SecondThird
ThirdFirst ThirdSecond ThirdThird
foo bar foobar
因此,尽管长度不同,子列表中的每个项目在一列中都是左对齐的。
我已经尝试过非常复杂的列表理解,例如
lists = [['FirstFirst', 'FirstSecond', 'FirstThird'],
['SecondFirst', 'SecondSecond', 'SecondThird'],
['ThirdFirst', 'ThirdSecond', 'ThirdThird'],
['foo', 'bar', 'foobar']]
[print(f'{_[0]}{" " * (15 - len(_[0]))}{_[1]}{" " * (30 - len(_[0] + _[1] + " " * (15 - len(_[0]))))}{_[2]}') for _ in lists]
虽然这确实有效,但它非常暴力。
更糟糕的是,此列表理解完全不可扩展。如果我想向子列表中的每个项目添加另一个字符串,我将不得不向我的列表理解添加更多内容以使其仍然有效。此外,如果我希望两个列表具有不同的长度,一切都会被挫败。
执行此操作的更好方法是什么?
使用理解:
# first map each string to formatted string with white space
lists = [list(map(lambda item: f'{item:<20}', inner_list)) for inner_list in lists]
#then join them
lists = [''.join(item) for item in lists]
print('\n'.join(lists))
这里唯一的问题是 20 不能是一个变量,它需要硬编码
使用列表理解来解决副作用是一种糟糕的风格:你创建了一个完整的列表(这需要时间和内存),之后会被丢弃 - 使用简单的循环。
您需要计算每个单词的长度(在每一列中)。获取单词的最大长度很简单:
data = [['FirstFirst', 'FirstSecond', 'FirstThird'],
['SecondFirst', 'SecondSecond', 'SecondThird'],
['ThirdFirst', 'ThirdSecond', 'ThirdThird'],
['foo', 'verylongwordinsidehere', 'bar', ]] # changed to a longer one
# get max word length
max_len = max(len(i) for j in data for i in j)
# do not use list comp for printing side effect - use a simple loop
for inner in data:
for word in inner:
print(f"{word:{max_len}}",end=" | ") # and format the length into it
print()
得到
FirstFirst | FirstSecond | FirstThird |
SecondFirst | SecondSecond | SecondThird |
ThirdFirst | ThirdSecond | ThirdThird |
foo | verylongwordinsidehere | bar |
这看起来有点丑,如果你只得到每列的最大长度恕我直言会更好:
# transpose the list, get the max of each column and store in as dict[column]=legnth
col_len = {i:max(map(len,inner)) for i,inner in enumerate(zip(*data))}
# print(col_len) # {0: 11, 1: 22, 2: 11}
# print using the column index from enumerate to lookup this columns lenght
for inner in data:
for col,word in enumerate(inner):
print(f"{word:{col_len[col]}}",end=" | ")
print()
获得列宽调整后的输出:
FirstFirst | FirstSecond | FirstThird |
SecondFirst | SecondSecond | SecondThird |
ThirdFirst | ThirdSecond | ThirdThird |
foo | verylongwordinsidehere | bar |
见
- Understanding nested list comprehension 以更好地理解
max_len = max(len(i) for j in data for i in j)
的作用
- python matrix transpose and zip 以查看如何使用
zip()
转置列表的列表
如果你需要让它更短,你可以使用 ' | '.join()
来打印列表:
# do not use list comp for printing side effect - use a simple loop
for inner in data:
print( ' | '.join( (f"{word:{max_len}}" for word in inner)))
如果你还需要打印不均匀的列表,zip() 不会做 - 你可以绕过它(研究 itertiols.zip_longest)但如果你真的需要它,请提出一个新的数据问题在你尝试做一些你需要做的事情之后。
我有一个结构为 [[s: str, s: str, s: str]]
的列表列表,其中可以有任意数量的项目(列表)。
我想像这样在列中干净地打印它:
FirstFirst FirstSecond FirstThird
SecondFirst SecondSecond SecondThird
ThirdFirst ThirdSecond ThirdThird
foo bar foobar
因此,尽管长度不同,子列表中的每个项目在一列中都是左对齐的。
我已经尝试过非常复杂的列表理解,例如
lists = [['FirstFirst', 'FirstSecond', 'FirstThird'],
['SecondFirst', 'SecondSecond', 'SecondThird'],
['ThirdFirst', 'ThirdSecond', 'ThirdThird'],
['foo', 'bar', 'foobar']]
[print(f'{_[0]}{" " * (15 - len(_[0]))}{_[1]}{" " * (30 - len(_[0] + _[1] + " " * (15 - len(_[0]))))}{_[2]}') for _ in lists]
虽然这确实有效,但它非常暴力。
更糟糕的是,此列表理解完全不可扩展。如果我想向子列表中的每个项目添加另一个字符串,我将不得不向我的列表理解添加更多内容以使其仍然有效。此外,如果我希望两个列表具有不同的长度,一切都会被挫败。
执行此操作的更好方法是什么?
使用理解:
# first map each string to formatted string with white space
lists = [list(map(lambda item: f'{item:<20}', inner_list)) for inner_list in lists]
#then join them
lists = [''.join(item) for item in lists]
print('\n'.join(lists))
这里唯一的问题是 20 不能是一个变量,它需要硬编码
使用列表理解来解决副作用是一种糟糕的风格:你创建了一个完整的列表(这需要时间和内存),之后会被丢弃 - 使用简单的循环。
您需要计算每个单词的长度(在每一列中)。获取单词的最大长度很简单:
data = [['FirstFirst', 'FirstSecond', 'FirstThird'],
['SecondFirst', 'SecondSecond', 'SecondThird'],
['ThirdFirst', 'ThirdSecond', 'ThirdThird'],
['foo', 'verylongwordinsidehere', 'bar', ]] # changed to a longer one
# get max word length
max_len = max(len(i) for j in data for i in j)
# do not use list comp for printing side effect - use a simple loop
for inner in data:
for word in inner:
print(f"{word:{max_len}}",end=" | ") # and format the length into it
print()
得到
FirstFirst | FirstSecond | FirstThird |
SecondFirst | SecondSecond | SecondThird |
ThirdFirst | ThirdSecond | ThirdThird |
foo | verylongwordinsidehere | bar |
这看起来有点丑,如果你只得到每列的最大长度恕我直言会更好:
# transpose the list, get the max of each column and store in as dict[column]=legnth
col_len = {i:max(map(len,inner)) for i,inner in enumerate(zip(*data))}
# print(col_len) # {0: 11, 1: 22, 2: 11}
# print using the column index from enumerate to lookup this columns lenght
for inner in data:
for col,word in enumerate(inner):
print(f"{word:{col_len[col]}}",end=" | ")
print()
获得列宽调整后的输出:
FirstFirst | FirstSecond | FirstThird |
SecondFirst | SecondSecond | SecondThird |
ThirdFirst | ThirdSecond | ThirdThird |
foo | verylongwordinsidehere | bar |
见
- Understanding nested list comprehension 以更好地理解
max_len = max(len(i) for j in data for i in j)
的作用 - python matrix transpose and zip 以查看如何使用
zip()
转置列表的列表
如果你需要让它更短,你可以使用 ' | '.join()
来打印列表:
# do not use list comp for printing side effect - use a simple loop
for inner in data:
print( ' | '.join( (f"{word:{max_len}}" for word in inner)))
如果你还需要打印不均匀的列表,zip() 不会做 - 你可以绕过它(研究 itertiols.zip_longest)但如果你真的需要它,请提出一个新的数据问题在你尝试做一些你需要做的事情之后。