如何将字典列表打印为对齐 table?
How to print a list of dicts as an aligned table?
因此,在使用格式说明符解决了有关对齐的多个问题后,我仍然无法弄清楚为什么数字数据以波浪方式打印到标准输出。
def create_data(soup_object,max_entry=None):
max_=max_entry
entry=dict()
for a in range(1,int(max_)+1):
entry[a]={'Key':a,
'Title':soup_object[a].div.text.strip(),
'Link':soup_object[a].div.a['href'],
'Seeds':soup_object[a](attrs={'align':'right'})[0].text.strip(),
'Leechers':soup_object[a](attrs={'align':'right'})[1].text.strip()}
yield entry[a]
tpb_get_data=tuple(create_data(soup_object=tpb_soup.body.table.find_all("tr"),max_entry=5))
for data in tpb_get_data:
print('{0} {1:<11} {2:<25} {3:<25} '.format(data['Key'], data['Title'], data['Seeds'],data['Leechers']))
我尝试将 f-strings 与格式说明符一起使用,但它仍然按以下方式打印数据,有人可以帮我解决这个问题吗?
1 Salvation.S02E11.HDTV.x264-KILLERS 262 19
2 Salvation.S02E13.WEB.x264-TBS[ettv] 229 25
3 Salvation.S02E08.HDTV.x264-KILLERS 178 21
4 Salvation.S02E01.HDTV.x264-KILLERS 144 11
5 Salvation.S02E09.HDTV.x264-SVA[ettv] 129 14
我已经阅读了大部分关于此的问题,我想知道是否有原始方法而不是使用像 tabulate 这样的库,它做得很好。但我也想学习如何在没有任何库的情况下做到这一点。
你得到一个错位的结果,因为你没有计算正确的标题长度。您只保留了 11 个字符,第一个字符已经有 34 个字符了。
最简单的方法是让您的程序对您有用:
key_len,title_len,seed_len,leech_len = ( max(len(item[itemname]) for item in tpb_get_data) for itemname in ['Key','Title','Seeds','Leechers'] )
fmtstring = '{{:{:d}}} {{:{:d}}} {{:{:d}}} {{:{:d}}}'.format(key_len,title_len,seed_len,leech_len)
for data in tpb_get_data:
print(fmtstring.format(data['Key'], data['Title'], data['Seeds'],data['Leechers']))
更好的结果
1 Salvation.S02E11.HDTV.x264-KILLERS 262 19
2 Salvation.S02E13.WEB.x264-TBS[ettv] 229 25
3 Salvation.S02E08.HDTV.x264-KILLERS 178 21
4 Salvation.S02E01.HDTV.x264-KILLERS 144 11
5 Salvation.S02E09.HDTV.x264-SVA[ettv] 129 14
(仅附加)
这是一种更通用的方法,它使用 to-print 键名称列表,并且能够即时生成所有其他所需的变量。它不需要对变量的名称进行硬编码,也不需要固定它们的顺序——顺序取自该列表。调整项目以显示全部在一个地方:同一个列表,get_items
。可以在 fmtstring
行中更改输出分隔符,例如在项目之间使用制表符或更多空格。
get_items = ['Key','Title','Leechers','Seeds']
lengths = ( max(len(item[itemname]) for item in tpb_get_data) for itemname in get_items )
fmtstring = ' '.join(['{{:{:d}}}' for i in range(len(get_items))]).format(*lengths)
for data in tpb_get_data:
print(fmtstring.format(*[data[key] for key in get_items]))
它的工作原理如下:
lengths
列表填充了取自 get_items
列表的每个命名键的最大长度。
- 这个returns一个
list
; fmtstring
为每个项目重复格式指令 {:d}
并填写数字。外部 {{:
和 }}
被 format
翻译成 {:
和 }
所以最终结果将是 {:[=42=每个长度的 ]number</em>}
。这些单独的格式字符串连接成一个较长的格式字符串。
- 最后,对实际数据的循环打印来自
get_items
的项目。列表理解查找它们; *
表示法强制列表 'written out' 作为单独的值,而不是将整个列表作为一个返回。
感谢 @Georgy 建议寻找一个不太硬编码的品种。
如前所述,您计算的字符串长度不正确。
不要对它们进行硬编码,而是将此任务委托给您的程序。
这是一个通用的方法:
from operator import itemgetter
from typing import (Any,
Dict,
Iterable,
Iterator,
List,
Sequence)
def max_length(objects: Iterable[Any]) -> int:
"""Returns maximum string length of a sequence of objects"""
strings = map(str, objects)
return max(map(len, strings))
def values_max_length(dicts: Sequence[Dict[str, Any]],
*,
key: str) -> int:
"""Returns maximum string length of dicts values for specific key"""
return max_length(map(itemgetter(key), dicts))
def to_aligned_data(dicts: Sequence[Dict[str, Any]],
*,
keys: List[str],
sep: str = ' ') -> Iterator[str]:
"""Prints a sequence of dicts in a form of a left aligned table"""
lengths = (values_max_length(dicts, key=key)
for key in keys)
format_string = sep.join(map('{{:{}}}'.format, lengths))
for row in map(itemgetter(*keys), dicts):
yield format_string.format(*row)
示例:
data = [{'Key': '1',
'Title': 'Salvation.S02E11.HDTV.x264-KILLERS',
'Seeds': '262',
'Leechers': '19'},
{'Key': '2',
'Title': 'Salvation.S02E13.WEB.x264-TBS[ettv]',
'Seeds': '229',
'Leechers': '25'},
{'Key': '3',
'Title': 'Salvation.S02E08.HDTV.x264-KILLERS',
'Seeds': '178',
'Leechers': '21'},
{'Key': '4',
'Title': 'Salvation.S02E01.HDTV.x264-KILLERS',
'Seeds': '144',
'Leechers': '11'},
{'Key': '5',
'Title': 'Salvation.S02E09.HDTV.x264-SVA[ettv]',
'Seeds': '129',
'Leechers': '14'}]
keys = ['Key', 'Title', 'Seeds', 'Leechers']
print(*to_aligned_data(data, keys=keys),
sep='\n')
# 1 Salvation.S02E11.HDTV.x264-KILLERS 262 19
# 2 Salvation.S02E13.WEB.x264-TBS[ettv] 229 25
# 3 Salvation.S02E08.HDTV.x264-KILLERS 178 21
# 4 Salvation.S02E01.HDTV.x264-KILLERS 144 11
# 5 Salvation.S02E09.HDTV.x264-SVA[ettv] 129 14
keys = ['Title', 'Leechers']
print(*to_aligned_data(data, keys=keys),
sep='\n')
# Salvation.S02E11.HDTV.x264-KILLERS 19
# Salvation.S02E13.WEB.x264-TBS[ettv] 25
# Salvation.S02E08.HDTV.x264-KILLERS 21
# Salvation.S02E01.HDTV.x264-KILLERS 11
# Salvation.S02E09.HDTV.x264-SVA[ettv] 14
keys = ['Key', 'Title', 'Seeds', 'Leechers']
print(*to_aligned_data(data, keys=keys, sep=' ' * 5),
sep='\n')
# 1 Salvation.S02E11.HDTV.x264-KILLERS 262 19
# 2 Salvation.S02E13.WEB.x264-TBS[ettv] 229 25
# 3 Salvation.S02E08.HDTV.x264-KILLERS 178 21
# 4 Salvation.S02E01.HDTV.x264-KILLERS 144 11
# 5 Salvation.S02E09.HDTV.x264-SVA[ettv] 129 14
有关更多信息,请参阅 docs。还有对齐的例子。
很好的答案购买@Jongware,只是为了
- 让它更通用一些
- 没有硬编码项目
- 打印任何类型的值,而不仅仅是字符串 -
这里是:
def print_list_of_dicts_as_table(list_of_dicts, keys=None):
# assuming all dicts have same keys
first_entry = list_of_dicts[0]
if keys is None:
keys = first_entry.keys()
num_keys = len(keys)
max_key_lens = [
max(len(str(item[k])) for item in list_of_dicts) for k in keys
]
for k_idx, k in enumerate(keys):
max_key_lens[k_idx] = max(max_key_lens[k_idx], len(k))
fmtstring = (' | '.join(['{{:{:d}}}'] * num_keys)).format(*max_key_lens)
print(fmtstring.format(*first_entry.keys()))
print(fmtstring.format(*['-'*key_len for key_len in max_key_lens]))
for entry in list_of_dicts:
print(fmtstring.format(*entry.values()))
用法示例:
a=[{'a':'asdd','b':'asd'},{'a':'a','b':'asdsd'},{'a':1,'b':232323}]
print_list_of_dicts_as_table(a)
输出:
a | b
---- | ------
asdd | asd
a | asdsd
1 | 232323
因此,在使用格式说明符解决了有关对齐的多个问题后,我仍然无法弄清楚为什么数字数据以波浪方式打印到标准输出。
def create_data(soup_object,max_entry=None):
max_=max_entry
entry=dict()
for a in range(1,int(max_)+1):
entry[a]={'Key':a,
'Title':soup_object[a].div.text.strip(),
'Link':soup_object[a].div.a['href'],
'Seeds':soup_object[a](attrs={'align':'right'})[0].text.strip(),
'Leechers':soup_object[a](attrs={'align':'right'})[1].text.strip()}
yield entry[a]
tpb_get_data=tuple(create_data(soup_object=tpb_soup.body.table.find_all("tr"),max_entry=5))
for data in tpb_get_data:
print('{0} {1:<11} {2:<25} {3:<25} '.format(data['Key'], data['Title'], data['Seeds'],data['Leechers']))
我尝试将 f-strings 与格式说明符一起使用,但它仍然按以下方式打印数据,有人可以帮我解决这个问题吗?
1 Salvation.S02E11.HDTV.x264-KILLERS 262 19
2 Salvation.S02E13.WEB.x264-TBS[ettv] 229 25
3 Salvation.S02E08.HDTV.x264-KILLERS 178 21
4 Salvation.S02E01.HDTV.x264-KILLERS 144 11
5 Salvation.S02E09.HDTV.x264-SVA[ettv] 129 14
我已经阅读了大部分关于此的问题,我想知道是否有原始方法而不是使用像 tabulate 这样的库,它做得很好。但我也想学习如何在没有任何库的情况下做到这一点。
你得到一个错位的结果,因为你没有计算正确的标题长度。您只保留了 11 个字符,第一个字符已经有 34 个字符了。
最简单的方法是让您的程序对您有用:
key_len,title_len,seed_len,leech_len = ( max(len(item[itemname]) for item in tpb_get_data) for itemname in ['Key','Title','Seeds','Leechers'] )
fmtstring = '{{:{:d}}} {{:{:d}}} {{:{:d}}} {{:{:d}}}'.format(key_len,title_len,seed_len,leech_len)
for data in tpb_get_data:
print(fmtstring.format(data['Key'], data['Title'], data['Seeds'],data['Leechers']))
更好的结果
1 Salvation.S02E11.HDTV.x264-KILLERS 262 19
2 Salvation.S02E13.WEB.x264-TBS[ettv] 229 25
3 Salvation.S02E08.HDTV.x264-KILLERS 178 21
4 Salvation.S02E01.HDTV.x264-KILLERS 144 11
5 Salvation.S02E09.HDTV.x264-SVA[ettv] 129 14
(仅附加)
这是一种更通用的方法,它使用 to-print 键名称列表,并且能够即时生成所有其他所需的变量。它不需要对变量的名称进行硬编码,也不需要固定它们的顺序——顺序取自该列表。调整项目以显示全部在一个地方:同一个列表,get_items
。可以在 fmtstring
行中更改输出分隔符,例如在项目之间使用制表符或更多空格。
get_items = ['Key','Title','Leechers','Seeds']
lengths = ( max(len(item[itemname]) for item in tpb_get_data) for itemname in get_items )
fmtstring = ' '.join(['{{:{:d}}}' for i in range(len(get_items))]).format(*lengths)
for data in tpb_get_data:
print(fmtstring.format(*[data[key] for key in get_items]))
它的工作原理如下:
lengths
列表填充了取自get_items
列表的每个命名键的最大长度。- 这个returns一个
list
;fmtstring
为每个项目重复格式指令{:d}
并填写数字。外部{{:
和}}
被format
翻译成{:
和}
所以最终结果将是{:[=42=每个长度的 ]number</em>}
。这些单独的格式字符串连接成一个较长的格式字符串。 - 最后,对实际数据的循环打印来自
get_items
的项目。列表理解查找它们;*
表示法强制列表 'written out' 作为单独的值,而不是将整个列表作为一个返回。
感谢 @Georgy 建议寻找一个不太硬编码的品种。
如前所述,您计算的字符串长度不正确。
不要对它们进行硬编码,而是将此任务委托给您的程序。
这是一个通用的方法:
from operator import itemgetter
from typing import (Any,
Dict,
Iterable,
Iterator,
List,
Sequence)
def max_length(objects: Iterable[Any]) -> int:
"""Returns maximum string length of a sequence of objects"""
strings = map(str, objects)
return max(map(len, strings))
def values_max_length(dicts: Sequence[Dict[str, Any]],
*,
key: str) -> int:
"""Returns maximum string length of dicts values for specific key"""
return max_length(map(itemgetter(key), dicts))
def to_aligned_data(dicts: Sequence[Dict[str, Any]],
*,
keys: List[str],
sep: str = ' ') -> Iterator[str]:
"""Prints a sequence of dicts in a form of a left aligned table"""
lengths = (values_max_length(dicts, key=key)
for key in keys)
format_string = sep.join(map('{{:{}}}'.format, lengths))
for row in map(itemgetter(*keys), dicts):
yield format_string.format(*row)
示例:
data = [{'Key': '1',
'Title': 'Salvation.S02E11.HDTV.x264-KILLERS',
'Seeds': '262',
'Leechers': '19'},
{'Key': '2',
'Title': 'Salvation.S02E13.WEB.x264-TBS[ettv]',
'Seeds': '229',
'Leechers': '25'},
{'Key': '3',
'Title': 'Salvation.S02E08.HDTV.x264-KILLERS',
'Seeds': '178',
'Leechers': '21'},
{'Key': '4',
'Title': 'Salvation.S02E01.HDTV.x264-KILLERS',
'Seeds': '144',
'Leechers': '11'},
{'Key': '5',
'Title': 'Salvation.S02E09.HDTV.x264-SVA[ettv]',
'Seeds': '129',
'Leechers': '14'}]
keys = ['Key', 'Title', 'Seeds', 'Leechers']
print(*to_aligned_data(data, keys=keys),
sep='\n')
# 1 Salvation.S02E11.HDTV.x264-KILLERS 262 19
# 2 Salvation.S02E13.WEB.x264-TBS[ettv] 229 25
# 3 Salvation.S02E08.HDTV.x264-KILLERS 178 21
# 4 Salvation.S02E01.HDTV.x264-KILLERS 144 11
# 5 Salvation.S02E09.HDTV.x264-SVA[ettv] 129 14
keys = ['Title', 'Leechers']
print(*to_aligned_data(data, keys=keys),
sep='\n')
# Salvation.S02E11.HDTV.x264-KILLERS 19
# Salvation.S02E13.WEB.x264-TBS[ettv] 25
# Salvation.S02E08.HDTV.x264-KILLERS 21
# Salvation.S02E01.HDTV.x264-KILLERS 11
# Salvation.S02E09.HDTV.x264-SVA[ettv] 14
keys = ['Key', 'Title', 'Seeds', 'Leechers']
print(*to_aligned_data(data, keys=keys, sep=' ' * 5),
sep='\n')
# 1 Salvation.S02E11.HDTV.x264-KILLERS 262 19
# 2 Salvation.S02E13.WEB.x264-TBS[ettv] 229 25
# 3 Salvation.S02E08.HDTV.x264-KILLERS 178 21
# 4 Salvation.S02E01.HDTV.x264-KILLERS 144 11
# 5 Salvation.S02E09.HDTV.x264-SVA[ettv] 129 14
有关更多信息,请参阅 docs。还有对齐的例子。
很好的答案购买@Jongware,只是为了
- 让它更通用一些
- 没有硬编码项目
- 打印任何类型的值,而不仅仅是字符串 -
这里是:
def print_list_of_dicts_as_table(list_of_dicts, keys=None):
# assuming all dicts have same keys
first_entry = list_of_dicts[0]
if keys is None:
keys = first_entry.keys()
num_keys = len(keys)
max_key_lens = [
max(len(str(item[k])) for item in list_of_dicts) for k in keys
]
for k_idx, k in enumerate(keys):
max_key_lens[k_idx] = max(max_key_lens[k_idx], len(k))
fmtstring = (' | '.join(['{{:{:d}}}'] * num_keys)).format(*max_key_lens)
print(fmtstring.format(*first_entry.keys()))
print(fmtstring.format(*['-'*key_len for key_len in max_key_lens]))
for entry in list_of_dicts:
print(fmtstring.format(*entry.values()))
用法示例:
a=[{'a':'asdd','b':'asd'},{'a':'a','b':'asdsd'},{'a':1,'b':232323}]
print_list_of_dicts_as_table(a)
输出:
a | b
---- | ------
asdd | asd
a | asdsd
1 | 232323