在python中创build好的列输出
我正在试图创build一个很好的列表在Python中用于我创build的命令行pipe理工具。
基本上,我想要一个像这样的列表:
[['a', 'b', 'c'], ['aaaaaaaaaa', 'b', 'c'], ['a', 'bbbbbbbbbb', 'c']]
变成:
abc aaaaaaaaaa bc a bbbbbbbbbb c
使用普通的选项卡不会在这里做的伎俩,因为我不知道每行中最长的数据。
这与Linux中'column -t'的行为是一样的
$ echo -e "abc\naaaaaaaaaa bc\na bbbbbbbbbb c" abc aaaaaaaaaa bc a bbbbbbbbbb c $ echo -e "abc\naaaaaaaaaa bc\na bbbbbbbbbb c" | column -t abc aaaaaaaaaa bc a bbbbbbbbbb c
我已经四处寻找各种python库来做到这一点,但找不到任何有用的东西。
data = [['a', 'b', 'c'], ['aaaaaaaaaa', 'b', 'c'], ['a', 'bbbbbbbbbb', 'c']] col_width = max(len(word) for row in data for word in row) + 2 # padding for row in data: print "".join(word.ljust(col_width) for word in row) abc aaaaaaaaaa bca bbbbbbbbbb c
这是计算最长的数据input以确定列宽,然后使用.ljust()
在打印每列时添加必要的填充。
在Python 2.6+中,可以使用以下格式string将列设置为最less20个字符,并将文本alignment到右侧。
>>> table_data = [['a', 'b', 'c'], ['aaaaaaaaaa', 'b', 'c'], ['a', 'bbbbbbbbbb', 'c']] >>> for row in table_data: ... print("{: >20} {: >20} {: >20}".format(*row)) ... abc aaaaaaaaaa bc a bbbbbbbbbb c
我来到这里有相同的要求,但@lvc和@ Preet的答案似乎更多内联column -t
产生的列中有不同的宽度:
>>> rows = [ ['a', 'b', 'c', 'd'] ... , ['aaaaaaaaaa', 'b', 'c', 'd'] ... , ['a', 'bbbbbbbbbb', 'c', 'd'] ... ] ...
>>> widths = [max(map(len, col)) for col in zip(*rows)] >>> for row in rows: ... print " ".join((val.ljust(width) for val, width in zip(row, widths))) ... abcd aaaaaaaaaa bcd a bbbbbbbbbb cd
你必须通过2次这样做:
- 获得每列的最大宽度。
- 使用
str.ljust()
和str.rjust()
从第一遍使用我们的最大宽度知识来格式化列。
像这样调换列是压缩工作:
>>> a = [['a', 'b', 'c'], ['aaaaaaaaaa', 'b', 'c'], ['a', 'bbbbbbbbbb', 'c']] >>> list(zip(*a)) [('a', 'aaaaaaaaaa', 'a'), ('b', 'b', 'bbbbbbbbbb'), ('c', 'c', 'c')]
要find每列所需的长度,可以使用max
:
>>> trans_a = zip(*a) >>> [max(len(c) for c in b) for b in trans_a] [10, 10, 1]
你可以使用合适的填充来构造要传递的string:
>>> 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)) 'abc'
创build数据框的基于pandas
的解决scheme:
import pandas as pd l = [['a', 'b', 'c'], ['aaaaaaaaaa', 'b', 'c'], ['a', 'bbbbbbbbbb', 'c']] df = pd.DataFrame(l) print(df) 0 1 2 0 abc 1 aaaaaaaaaa bc 2 a bbbbbbbbbb c
要删除索引和标题值来创build输出,你可以使用to_string
方法:
result = df.to_string(index=False, header=False) print(result) abc aaaaaaaaaa bc a bbbbbbbbbb c
获得更喜欢的表
--------------------------------------------------- | First Name | Last Name | Age | Position | --------------------------------------------------- | John | Smith | 24 | Software | | | | | Engineer | --------------------------------------------------- | Mary | Brohowski | 23 | Sales | | | | | Manager | --------------------------------------------------- | Aristidis | Papageorgopoulos | 28 | Senior | | | | | Reseacher | ---------------------------------------------------
你可以使用这个Python配方 :
''' From http://code.activestate.com/recipes/267662-table-indentation/ PSF License ''' import cStringIO,operator def indent(rows, hasHeader=False, headerChar='-', delim=' | ', justify='left', separateRows=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 rowWrapper(row): newRows = [wrapfunc(item).split('\n') for item in row] return [[substr or '' for substr in item] for item in map(None,*newRows)] # break each logical row into one or more physical ones logicalRows = [rowWrapper(row) for row in rows] # columns of physical rows columns = map(None,*reduce(operator.add,logicalRows)) # get the maximum of each column by the string length of its items maxWidths = [max([len(str(item)) for item in column]) for column in columns] rowSeparator = headerChar * (len(prefix) + len(postfix) + sum(maxWidths) + \ len(delim)*(len(maxWidths)-1)) # select the appropriate justify method justify = {'center':str.center, 'right':str.rjust, 'left':str.ljust}[justify.lower()] output=cStringIO.StringIO() if separateRows: print >> output, rowSeparator for physicalRows in logicalRows: for row in physicalRows: print >> output, \ prefix \ + delim.join([justify(str(item),width) for (item,width) in zip(row,maxWidths)]) \ + postfix if separateRows or hasHeader: print >> output, rowSeparator; hasHeader=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 reduce(lambda line, word, width=width: '%s%s%s' % (line, ' \n'[(len(line[line.rfind('\n')+1:]) + len(word.split('\n',1)[0] ) >= width)], word), text.split(' ') ) import re def wrap_onspace_strict(text, width): """Similar to wrap_onspace, but enforces the width constraint: words longer than width are split.""" wordRegex = re.compile(r'\S{'+str(width)+r',}') return wrap_onspace(wordRegex.sub(lambda m: wrap_always(m.group(),width),text),width) import math 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 xrange(int(math.ceil(1.*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, hasHeader=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, hasHeader=True, separateRows=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 | #---------------------------------------------
Python配方页面包含一些改进。
我意识到这个问题是古老的,但我不明白Antak的答案,不想使用库,所以我推出了自己的解决scheme。
解决scheme假设logging是二维数组,logging长度都一样,而且这些字段都是string。
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