1

与此相同的问题,但对于 python。如果我有清单

['a','b','cdefg','jk','lmnopqr','st','uv','wxyz',1,2,3,4]

我想打印出类似于 bash 中 ls 命令的默认输出的内容,例如

[ 'a',   'b',        'cdefg',
  'jk',  'st',       'lm',
  'no',  'pqrstuv',  'wxyz',  
  1,     2,          3,
  4,     ]

目标是一次在屏幕上最大化视觉上可解析的数据。我只能找到 pprint 库,对于简单列表,它要么打印为默认值,要么每行打印一个。这样的东西已经存在了吗?

4

2 回答 2

4

感谢大家的想法并澄清确实没有现成的解决方案。我编写了我想要的代码,代码如下。在宽度为 80 个字符的终端中

pprint_list( [ string.lowercase[i % 26]*random.randint(1,20) for i in range(8) ] )

打印为

[ 'aaaa',         'bbbbbbbbbbbbbbb',   'ccccccccccccccccccc',  'd',  
  'eeeeeeeeeee',  'ffffffffffffffff',  'gggggggggggggggg',     'h'   ]

查看代码显示,在确定如何调整列大小时显然存在一些开销,更多的条目和更宽的终端需要更多的计算,但是将条目数从 8 增加到 50000 并没有太多延迟时间,所以我觉得我很满意。

此代码依赖于此处的 get_terminal_size 函数。

#!/usr/bin/env python
def pprint_list(input_list):
    (term_width, term_height) = get_terminal_size()
    if len( str(input_list) ) <= term_width:
        print input_list
        return

    repr_list = [repr(x) for x in input_list]
    min_chars_between = 3 # a comma and two spaces
    usable_term_width = term_width - 3 # For '[ ' and ']' at beginning and end
    min_element_width = min( len(x) for x in repr_list ) + min_chars_between
    max_element_width = max( len(x) for x in repr_list ) + min_chars_between
    if max_element_width >= usable_term_width:
        ncol = 1
        col_widths = [1]
    else:
        # Start with max possible number of columns and reduce until it fits
        ncol = min( len(repr_list), usable_term_width / min_element_width  )
        while True:
            col_widths = [ max( len(x) + min_chars_between \
                                for j, x in enumerate( repr_list ) if j % ncol == i ) \
                                for i in range(ncol) ]
            if sum( col_widths ) <= usable_term_width: break
            else: ncol -= 1

    sys.stdout.write('[ ')
    for i, x in enumerate(repr_list):
        if i != len(repr_list)-1: x += ','
        sys.stdout.write( x.ljust( col_widths[ i % ncol ] ) )
        if i == len(repr_list) - 1:
            sys.stdout.write(']\n')
        elif (i+1) % ncol == 0:
            sys.stdout.write('\n  ')
于 2014-07-30T01:48:09.017 回答
4
def columnify(iterable):
    # First convert everything to its repr
    strings = [repr(x) for x in iterable]
    # Now pad all the strings to match the widest
    widest = max(len(x) for x in strings)
    padded = [x.ljust(widest) for x in strings]
    return padded

现在您应该能够使用pprint.pprint(compact=True), 或textwrap, 或其他工具来获得所需的格式。

但是如果你想手动做,做任何你想做的事情都不是太难。例如:

def colprint(iterable, width=72):
    columns = columnify(iterable)
    colwidth = len(columns[0])+2
    perline = (width-4) // colwidth
    print('[ ', end='')
    for i, column in enumerate(columns):
        print(column, end=', ')
        if i % perline == perline-1:
            print('\n  ', end='')
    print(' ]')

所以:

>>> arr = ['a', 'b', 'cdefg', 'jk', 'lmnopqr', 'st', 'uv', 'wxyz', 1, 2, 3, 4]
>>> colprint(arr, 60)
[ 'a'      , 'b'      , 'cdefg'  , 'jk'     , 'lmnopqr',
  'st'     , 'uv'     , 'wxyz'   , 1        , 2        ,
  3        , 4        ,  ]

这仍然不会为您提供确切的ls功能;例如,ls有一些启发式方法试图确保“太长”的文件名不计入最大宽度,而是跨越多列。如果你真的想把所有的东西都做的一模一样ls,你可能需要查看源代码并从 C 翻译成 Python……</p>

另外,看看pprint。每当一个模块的文档以指向源代码的链接开始时,这意味着该模块旨在用作有用的示例代码,并且它本身也是有用的。因此,如果您想查看它用于确定何时分割线的规则(基于compact标志和宽度),您应该能够从那里弄清楚。

于 2014-07-30T00:04:58.520 回答