如何将字典列表打印为对齐表?

时间:2018-10-26 09:16:20

标签: python python-3.x terminal string-formatting text-alignment

因此,在使用格式说明符解决了有关对齐的多个问题之后,我仍然无法弄清为什么将数字数据以波浪的方式打印到stdout。

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这样的库做得很好。但是我也想学习如何在没有任何库的情况下做到这一点。

3 个答案:

答案 0 :(得分:3)

由于未正确计算标题的长度,因此得到未对齐的结果。您只保留了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

(仅限其他)

这是一种更通用的方法,它使用要打印的键名列表,并能够即时生成所有其他必需的变量。它不需要对变量名进行硬编码,也不需要固定它们的顺序-顺序是从该列表中获取的。要显示所有项目的调整都放在一个位置:同一列表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]))

它的工作原理如下:

  1. lengths列表中填充了从get_items列表中提取的每个命​​名键的最大长度。
  2. 这将返回listfmtstring对以上每一项重复格式指令{:d},并填写数字。外部{{:}}format转换为{:},因此对于每个长度,最终结果将是{:number}。这些单独的格式字符串将合并为一个更长的格式字符串。
  3. 最后,在实际数据上循环将打印get_items中的项目。列表理解查找它们; *表示法强制将列表“写”为单独的值,而不是将整个列表返回为一个。

感谢@Georgy建议您寻找一种不太硬编码的品种。

答案 1 :(得分:1)

如前所述,您错误地计算了字符串的长度。
不用硬编码它们,而是将此任务委托给您的程序。

这是一种通用方法:

CREATE SEQUENCE shared_seq;

CREATE TABLE a (
   col1 bigint  DEFAULT nextval('shared_seq'),
   ...
);

CREATE TABLE b (
   col1 bigint  DEFAULT nextval('shared_seq'),
   ...
);

示例:

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)

有关更多信息,请参见docs。也有对齐的示例。

答案 2 :(得分:0)

很好的答案购买@Jongware,只是为了

  1. 让它更通用一些
  2. 没有硬编码的项目
  3. 打印任何类型的值,而不仅仅是字符串 -

这里是:

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