2009-10-06 4 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

Во-первых, это не очень хорошая идея использовать Dict в качестве имени переменной Во-вторых, что вы пытаетесь для печати здесь есть список, dict использует {} и: для разделения ключей и значений –

+3

-1: Название вопроса говорит «список» - полное дублирование. В вопросе говорится «dict». Образец кода - это список - полное дублирование. Вы хотите, чтобы список преобразовывался в dict и печатался? Если да, исправьте вопрос, чтобы описать то, что вы действительно хотите. –

+0

Я скорректировал описание и пример кода в соответствии с рекомендациями. Название и описание теперь отражают мою цель. Спасибо за исправления. –

ответ

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

+0

Спасибо, исправлено :) –

+0

Я принимаю это как ответ, потому что я заставил его работать надежно в кратчайшие сроки - и я могу это понять. Хотя было бы лучше иметь динамическую многоколоночную отчетность в качестве некоторых других ответов, я не мог заставить их работать надежно (вероятно, потому, что я не мог следовать логике в них) - иногда элементы удаляются из когда он растет/сжимается, или они больше не выстраиваются в столбцы. Спасибо Аарону! –

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

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

горизонтальный порядок, возможно, это не то, что вы хотите –

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, вы можете заполнить ее, добавив несколько пустых строк в конец –

-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, с немного более вещим синтаксисом. Это может сделать некоторые из вышеперечисленных ответов более понятными.

>>> 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] 

почтового

Архивирование списки (или другие итерируемые) генерируют кортежи элементов списков. Например:

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

Не могли бы вы рассказать о том, что происходит в zip (глупый ...)? –

+0

Добавлено объяснение по просьбе @matt wilkie – Aman

+0

Отличная экспликация, спасибо! –

0

Найдено этот вопрос как встретил почти ту же задачу. И я создал функцию для печати списка в нескольких столбцах с числом столбцов в качестве параметра. Возможно, это не так элегантно, как однострочные решения, но это может быть полезно для кого-то.

Однако он обрабатывает неполные списки, например: он может распечатать список из 11 в 3 строках.

Функция расщепляется для лучшей читаемости:

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

Вдохновленный ответом гимеля, 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). Просто потому, что c.ljust не работал с моими списками. В 3-й последней строке, а также len (str (item)), предварительно рассчитайте длины таким же образом. –

+0

@ErikKruus спасибо, внесли изменения на этот счет. Теперь я создаю новый список из входящего obj, который преобразуется в строки. Предотвращает необходимость использования нескольких str() и защищает входящий объект от редактирования. – ozagon

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') 
Смежные вопросы