2009-10-06 63 views
12

這與How to print a list in Python 「nicely」類似,但我希望更好地打印出列表 - 沒有括號和撇號和逗號,甚至在列中更好。如何更好地打印列表?

foolist = ['exiv2-devel', 'mingw-libs', 'tcltk-demos', 'fcgi', 'netcdf', 
    'pdcurses-devel',  'msvcrt', 'gdal-grass', 'iconv', 'qgis-devel', 
    'qgis1.1', 'php_mapscript'] 

evenNicerPrint(foolist) 

期望的結果:

exiv2-devel  msvcrt   
mingw-libs  gdal-grass  
tcltk-demos  iconv   
fcgi    qgis-devel  
netcdf   qgis1.1  
pdcurses-devel php_mapscript 

的感謝!

+1

首先,它是不使用字典作爲變量名 其次是一個好主意,那東西你想在這裏打印是一個列表,一個字典使用{}和:分隔鍵和值 – 2009-10-06 07:49:57

+3

-1:問題的標題是「list」 - 一個完整的重複。這個問題說「字典」。示例代碼是一個列表 - 一個完整的重複。你想將列表轉換爲字典並打印?如果是這樣,解決這個問題來描述你真正想要的東西。 – 2009-10-06 10:49:35

+0

我已經更正了建議的描述和示例代碼。標題和描述現在反映了我的目標。感謝您的更正。 – 2009-10-06 20:33:24

回答

10

簡單:

l = ['exiv2-devel', 'mingw-libs', 'tcltk-demos', 'fcgi', 'netcdf', 
    'pdcurses-devel',  'msvcrt', 'gdal-grass', 'iconv', 'qgis-devel', 
    'qgis1.1', 'php_mapscript'] 

if len(l) % 2 != 0: 
    l.append(" ") 

split = len(l)/2 
l1 = l[0:split] 
l2 = l[split:] 
for key, value in zip(l1,l2): 
    print '%-20s %s' % (key, value)   #python <2.6 
    print "{0:<20s} {1}".format(key, value) #python 2.6+ 
+0

不會產生輸出(數據在列主要順序) – falstro 2009-10-06 07:49:53

+0

謝謝,修正:) – 2009-10-06 08:06:44

+0

我接受這個作爲答案,因爲我可以在最短的時間內可靠地工作 - 而且我能理解它。雖然將動態多列報告作爲其他答案會更好,但是我無法使它們可靠地工作(可能是因爲我沒有能夠遵循其中的邏輯) - 有時項目會從列表隨着它的增長/縮小而變化,或者不再按列排列。謝謝Aaron! – 2009-10-07 23:25:30

3

如果數據是在已提供的格式,它是多一點的工作


>>> d = ['exiv2-devel', 'mingw-libs', 'tcltk-demos', 'fcgi', 'netcdf', 
...  'pdcurses-devel',  'msvcrt', 'gdal-grass', 'iconv', 'qgis-devel', 
...  'qgis1.1', 'php_mapscript'] 
>>> print "\n".join("%-20s %s"%(d[i],d[i+len(d)/2]) for i in range(len(d)/2)) 
exiv2-devel   msvcrt 
mingw-libs   gdal-grass 
tcltk-demos   iconv 
fcgi     qgis-devel 
netcdf    qgis1.1 
pdcurses-devel  php_mapscript 
+0

upvote單行解決方案 – Mizipzor 2009-10-29 16:25:51

5

formatting-a-list-of-text-into-columns

一個通用的解決方案,處理任何列數和奇數列表。 製表符分隔列,使用生成器表達式來節省空間。

def fmtcols(mylist, cols): 
    lines = ("\t".join(mylist[i:i+cols]) for i in xrange(0,len(mylist),cols)) 
    return '\n'.join(lines) 
+0

水平排序,可能這不是你想要的 – 2013-10-09 19:13:02

5

的方式亞倫做它可以與兩個以上的colums


>>> l = ['exiv2-devel', 'mingw-libs', 'tcltk-demos', 'fcgi', 'netcdf', 
...  'pdcurses-devel',  'msvcrt', 'gdal-grass', 'iconv', 'qgis-devel', 
...  'qgis1.1', 'php_mapscript'] 
>>> cols = 4 
>>> split=[l[i:i+len(l)/cols] for i in range(0,len(l),len(l)/cols)] 
>>> for row in zip(*split): 
... print "".join(str.ljust(i,20) for i in row) 
... 
exiv2-devel   fcgi    msvcrt    qgis-devel   
mingw-libs   netcdf    gdal-grass   qgis1.1    
tcltk-demos   pdcurses-devel  iconv    php_mapscript  
+0

如果l的長度不是cols的倍數,可以通過在末尾添加一些空字符串來填充 – 2009-10-06 08:46:17

-1
from itertools import izip_longest, islice 
L = ['exiv2-devel', 'mingw-libs', 'tcltk-demos', 'fcgi', 'netcdf', 
    'pdcurses-devel',  'msvcrt', 'gdal-grass', 'iconv', 'qgis-devel', 
    'qgis1.1', 'php_mapscript'] 

def columnize(sequence, columns=2): 
    size, remainder = divmod(len(sequence), columns) 
    if remainder: 
     size += 1 
    slices = [islice(sequence, pos, pos + size) 
       for pos in xrange(0, len(sequence), size)] 
    return izip_longest(fillvalue='', *slices) 

for values in columnize(L): 
    print ' '.join(value.ljust(20) for value in values) 
12

這個答案將使用由@Aaron Digulla答案同樣的方法工作,稍有更Python語法。這可能會使以上答案更易於理解。

>>> for a,b,c in zip(foolist[::3],foolist[1::3],foolist[2::3]): 
>>>  print '{:<30}{:<30}{:<}'.format(a,b,c) 

exiv2-devel     mingw-libs     tcltk-demos 
fcgi       netcdf      pdcurses-devel 
msvcrt      gdal-grass     iconv 
qgis-devel     qgis1.1      php_mapscript 

這可以很容易地適應任何數量的列或變量列,這將導致類似的@gnibbler答案。間距可以根據屏幕寬度進行調整。


更新:按要求說明。

索引

foolist[::3]選擇的foolist每第三個元件。 foolist[1::3]選擇第三個元素,從第二個元素開始('1',因爲python使用零索引)。

In [2]: bar = [1,2,3,4,5,6,7,8,9] 
In [3]: bar[::3] 
Out[3]: [1, 4, 7] 

拉鍊

正在壓縮列表(或其他iterables)產生的列表中的元素的元組。例如:

In [5]: zip([1,2,3],['a','b','c'],['x','y','z']) 
Out[5]: [(1, 'a', 'x'), (2, 'b', 'y'), (3, 'c', 'z')] 

一起

把這些想法我們一起讓我們的解決方案:

for a,b,c in zip(foolist[::3],foolist[1::3],foolist[2::3]): 

在這裏,我們首先生成的foolist三「片」,由每一個三分每個索引元素和一個偏移量。單獨它們每個僅包含三分之一的列表。現在,當我們壓縮這些切片並迭代時,每次迭代都會給我們三個foolist的元素。

這正是我們想要的東西:

In [11]: for a,b,c in zip(foolist[::3],foolist[1::3],foolist[2::3]): 
    ....:  print a,b,c       
Out[11]: exiv2-devel mingw-libs tcltk-demos 
     fcgi netcdf pdcurses-devel 
     [etc] 

相反的:

In [12]: for a in foolist: 
    ....:  print a 
Out[12]: exiv2-devel 
     mingw-libs 
     [etc] 
+0

請您詳細說明什麼是發生在拉鍊(愚蠢的...)? – 2014-07-31 21:01:38

+0

根據@matt wilkie的要求添加解釋 – Aman 2014-08-04 08:09:33

+0

優秀的解釋,謝謝! – 2014-08-04 18:26:30

0

發現這個問題,作爲滿足幾乎相同的任務。我已經創建了函數來打印列數爲多列的列表作爲參數。也許不像單線解決方案那麼優雅,但它可能對某人有用。

但是,它處理不完整的列表,例如:它可以在3行中打印11列表。

功能分裂爲更好的可讀性:

def is_printable(my_list): 
    return len(my_list) > 0 

def create_empty_list(columns): 
    result = [] 
    for num in range(0, columns): 
     result.append([]) 
    return result 

def fill_empty_list(empty_list, my_list, columns): 
    column_depth = len(my_list)/columns if len(my_list) % columns == 0 else len(my_list)/columns + 1 
    item_index = 0 
    for column in range(0, columns): 
     while len(empty_list[column]) < column_depth: 
      if item_index < len(my_list): 
       empty_list[column].append(my_list[item_index]) 
      else: 
       empty_list[column].append(" ") # last column could be incomplete, fill it with space 
      item_index += 1 

def print_list_in_columns(my_list, columns=1): 
    if not is_printable(my_list): 
     print 'Nothing to print, sorry...' 
     return 
    column_width = 25 #(in symbols) Also can be calculated automatically 
    list_to_print = create_empty_list(columns) 
    fill_empty_list(list_to_print, my_list, columns) 
    iterators = ["it" + str(i) for i in range(0, columns)] 
    for iterators in zip(*list_to_print): 
     print ("".join(str.ljust(i, column_width) for i in iterators)) 

和呼叫部分:

foolist = ['exiv2-devel', 'mingw-libs', 'tcltk-demos', 'fcgi', 'netcdf', 
    'pdcurses-devel',  'msvcrt', 'gdal-grass', 'iconv', 'qgis-devel', 
    'qgis1.1', 'php_mapscript'] 

print_list_in_columns(foolist, 2) 
1

這裏是我的解決方案。 (Copy in GitHub gist

它將終端寬度作爲輸入,並只顯示可容納的列數。

def col_print(lines, term_width=80, indent=0, pad=2): 
    n_lines = len(lines) 
    if n_lines == 0: 
    return 

    col_width = max(len(line) for line in lines) 
    n_cols = int((term_width + pad - indent)/(col_width + pad)) 
    n_cols = min(n_lines, max(1, n_cols)) 

    col_len = int(n_lines/n_cols) + (0 if n_lines % n_cols == 0 else 1) 
    if (n_cols - 1) * col_len >= n_lines: 
    n_cols -= 1 

    cols = [lines[i*col_len : i*col_len + col_len] for i in range(n_cols)] 

    rows = list(zip(*cols)) 
    rows_missed = zip(*[col[len(rows):] for col in cols[:-1]]) 
    rows.extend(rows_missed) 

    for row in rows: 
    print(" "*indent + (" "*pad).join(line.ljust(col_width) for line in row)) 
0

下面是在python 3.4,可自動檢測端子的寬度和需要考慮它的溶液。在Linux和Mac上測試。

def column_print(list_to_print, column_width=40): 
    import os 
    term_height, term_width = os.popen('stty size', 'r').read().split() 
    total_columns = int(term_width) // column_width 
    total_rows = len(list_to_print) // total_columns 
    # ceil 
    total_rows = total_rows + 1 if len(list_to_print) % total_columns != 0 else total_rows 

    format_string = "".join(["{%d:<%ds}" % (c, column_width) \ 
      for c in range(total_columns)]) 
    for row in range(total_rows): 
     column_items = [] 
     for column in range(total_columns): 
      # top-down order 
      list_index = row + column*total_rows 
      # left-right order 
      #list_index = row*total_columns + column 
      if list_index < len(list_to_print): 
       column_items.append(list_to_print[list_index]) 
      else: 
       column_items.append("") 
     print(format_string.format(*column_items)) 
8

受gimel的回答啓發,above

import math 

def list_columns(obj, cols=4, columnwise=True, gap=4): 
    """ 
    Print the given list in evenly-spaced columns. 

    Parameters 
    ---------- 
    obj : list 
     The list to be printed. 
    cols : int 
     The number of columns in which the list should be printed. 
    columnwise : bool, default=True 
     If True, the items in the list will be printed column-wise. 
     If False the items in the list will be printed row-wise. 
    gap : int 
     The number of spaces that should separate the longest column 
     item/s from the next column. This is the effective spacing 
     between columns based on the maximum len() of the list items. 
    """ 

    sobj = [str(item) for item in obj] 
    if cols > len(sobj): cols = len(sobj) 
    max_len = max([len(item) for item in sobj]) 
    if columnwise: cols = int(math.ceil(float(len(sobj))/float(cols))) 
    plist = [sobj[i: i+cols] for i in range(0, len(sobj), cols)] 
    if columnwise: 
     if not len(plist[-1]) == cols: 
      plist[-1].extend(['']*(len(sobj) - len(plist[-1]))) 
     plist = zip(*plist) 
    printer = '\n'.join([ 
     ''.join([c.ljust(max_len + gap) for c in p]) 
     for p in plist]) 
    print printer 

結果(第二個滿足您的要求):

>>> list_columns(foolist) 
exiv2-devel  fcgi    msvcrt   qgis-devel   
mingw-libs  netcdf   gdal-grass  qgis1.1   
tcltk-demos  pdcurses-devel iconv    php_mapscript  

>>> list_columns(foolist, cols=2) 
exiv2-devel  msvcrt    
mingw-libs  gdal-grass   
tcltk-demos  iconv    
fcgi    qgis-devel   
netcdf   qgis1.1   
pdcurses-devel php_mapscript  

>>> list_columns(foolist, columnwise=False) 
exiv2-devel  mingw-libs  tcltk-demos  fcgi    
netcdf   pdcurses-devel msvcrt   gdal-grass   
iconv    qgis-devel  qgis1.1   php_mapscript  

>>> list_columns(foolist, gap=1) 
exiv2-devel fcgi   msvcrt   qgis-devel  
mingw-libs  netcdf   gdal-grass  qgis1.1   
tcltk-demos pdcurses-devel iconv   php_mapscript 
+0

建議str(c).ljust,因爲c.ljust不適用於我的列表項目。在第三行中,還有len(str(item)),以同樣的方式預先計算長度。 – 2016-09-02 12:50:05

+0

@ErikKruus謝謝,對此做了修改。我現在從傳入的obj中創建一個新的列表,並將其轉換爲字符串。防止需要多個str()並保護傳入的對象不被編輯。 – ozagon 2016-09-08 15:02:39

1

我的n列的解決方案擴展到@Aman的答案

def printMultiCol(l, n_cols, buffer_len=5): 
    """formats a list of strings, l, into n_cols with a separation of buffer_len""" 
    if not l: return [] # return if not iterable! 
    max_l = max(map(len, l)) 
    formatter = '{{:<{max_l}}}'.format(max_l=max_l+buffer_len)*n_cols 
    zip_me_up = [l[i::n_cols] for i in xrange(n_cols)] 
    max_zip_l = max(map(len, zip_me_up)) 
    zip_me_up = map(lambda x: x + ['']*(max_zip_l-len(x)), zip_me_up) 
    return [formatter.format(*undress_me) for undress_me in zip(*zip_me_up)] 

測試

搭建用隨機字符串長度測試

import random 
list_length = 16 
random_strings = [ 
    ''.join(random.choice('spameggsbaconbeanssausage') 
    for x in range(random.randint(1,10))) 
    for i in xrange(list_length) 
] 

print 'for 4 columns (equal length cols) ...\n{}'.format(
    '\n'.join(printMultiCol(random_strings, 4)) 
) 
print 'for 7 columns (odd length cols) ...\n{}'.format(
    '\n'.join(printMultiCol(random_strings, 5)) 
) 

返回

## -- End pasted text -- 
for 4 columns (equal length cols) ... 
sgsebpasgm  assgaesse  ossmeagan  ebesnagec 
mees   eeges   m    gcb 
sm    pbe   bbgaa   ganopabnn 
bmou   asbegu   a    psoge 


for 7 columns (odd length cols) ... 
sgsebpasgm  assgaesse  ossmeagan  ebesnagec  mees 
eeges   m    gcb   sm    pbe 
bbgaa   ganopabnn  bmou   asbegu   a 
psoge 
0

這是有用的,以允許不均勻列,而無需事先知道你能有多少列適合:

>>> words = [string.ascii_lowercase] + list(string.ascii_lowercase) 
>>> print format_list(words) 
abcdefghijklmnopqrstuvwxyz b d f h j l n p r t v x z 
a       c e g i k m o q s u w y 

對於示例:

>>> foolist = ['exiv2-devel', 'mingw-libs', 'tcltk-demos', 'fcgi', 
... 'netcdf', 'pdcurses-devel', 'msvcrt', 'gdal-grass', 'iconv', 
... 'qgis-devel', 'qgis1.1', 'php_mapscript'] 
>>> print format_list(foolist, spacing=4, width=31) 
exiv2-devel  msvcrt 
mingw-libs  gdal-grass 
tcltk-demos  iconv 
fcgi    qgis-devel 
netcdf   qgis1.1 
pdcurses-devel php_mapscript 

這是代碼。請注意,它還處理帶有ANSI顏色代碼的單詞(例如來自colorama包) - 它們不會混淆列寬。

ansi_pattern = re.compile(r'\x1b\[\d{1,2}m') 


def get_nchars(string): 
    """Return number of characters, omitting ANSI codes.""" 
    return len(ansi_pattern.sub('', string)) 


def format_list(items, indent=0, spacing=2, width=79): 
    """Return string listing items along columns. 

    items : sequence 
     List of items to display that must be directly convertible into 
     unicode strings. ANSI color codes may be present, and are taken 
     into account in determining column widths 
    indent : int 
     Number of spaces in left margin. 
    spacing : int 
     Number of spaces between columns. 
    width : int 
     Maximum number of characters per line, including indentation. 
    """ 
    if not items: 
     return u'' 
    # Ensure all items are strings 
    items = [unicode(item) for item in items] 
    # Estimate number of columns based on shortest and longest items 
    minlen = min(get_nchars(item) for item in items) 
    maxlen = max(get_nchars(item) for item in items) 
    # Assume one column with longest width, remaining with shortest. 
    # Use negative numbers for ceiling division. 
    ncols = 1 - (-(width - indent - maxlen) // (spacing + min(1, minlen))) 
    ncols = max(1, min(len(items), ncols)) 

    # Reduce number of columns until items fit (or only one column) 
    while ncols >= 1: 
     # Determine number of rows by ceiling division 
     nrows = -(-len(items) // ncols) 
     # Readjust to avoid empty last column 
     ncols = -(-len(items) // nrows) 
     # Split items into columns, and test width 
     columns = [items[i*nrows:(i+1)*nrows] for i in range(ncols)] 
     totalwidth = indent - spacing + sum(
      spacing + max(get_nchars(item) for item in column) 
      for column in columns 
      ) 
     # Stop if columns fit. Otherwise, reduce number of columns and 
     # try again. 
     if totalwidth <= width: 
      break 
     else: 
      ncols -= 1 

    # Pad all items to column width 
    for i, column in enumerate(columns): 
     colwidth = max(get_nchars(item) for item in column) 
     columns[i] = [ 
      item + ' ' * (colwidth - get_nchars(item)) 
      for item in column 
      ] 

    # Transpose into rows, and return joined rows 
    rows = list(itertools.izip_longest(*columns, fillvalue='')) 
    return '\n'.join(
     ' ' * indent + (u' ' * spacing).join(row).rstrip() 
     for row in rows 
     ) 
0

這樣的事情呢?

def strlistToColumns(strl, maxWidth, spacing=4): 

longest = max([len(s) for s in strl]) 
width = longest+spacing 

# compute numCols s.t. (numCols-1)*(longest+spacing)+longest < maxWidth 
numCols = 1 + (maxWidth-longest)//width 
C = range(numCols) 

# If len(strl) does not have a multiple of numCols, pad it with empty strings 
strl += [""]*(len(strl) % numCols) 
numRows = len(strl)/numCols 
colString = '' 

for r in range(numRows): 
    colString += "".join(["{"+str(c)+":"+str(width)+"}" \ 
     for c in C]+["\n"]).format(*(strl[numCols*r+c] \ 
     for c in C)) 

return colString 


if __name__ == '__main__': 

fruits = ['apple', 'banana', 'cantaloupe', 'durian', 'elderberry',   \ 
      'fig', 'grapefruit', 'honeydew', 'indonesian lime', 'jackfruit', \ 
      'kiwi', 'lychee', 'mango', 'orange', 'pomegranate', 'quince', \ 
      'raspberry', 'tangerine', 'ugli fruit', 'watermelon', 'xigua', 
      'yangmei', 'zinfandel grape'] 

cols = strlistToColumns(fruits, 80) 

print(cols) 

輸出

apple    banana    cantaloupe   durian 
elderberry   fig    grapefruit   honeydew 
indonesian lime jackfruit   kiwi    lychee 
mango    orange    pomegranate  quince 
raspberry   tangerine   ugli fruit   watermelon 
xigua    yangmei   zinfandel grape 
0
[print('{:20}'.format(key), end='\t') if (idx + 1) % 5 else print(key, end='\n') for idx, key in enumerate(list_variable)] 

for idx, key in enumerate(list_variable): 
    if (idx + 1) % 5: 
     print('{:20}'.format(key), end='\t') 
    else: 
     print(key, end='\n')