2009-10-06 21 views
12

Esto es similar a How to print a list in Python “nicely”, pero me gustaría imprimir la lista aún mejor, sin los corchetes, los apóstrofes y las comas, y aún mejor en las columnas.¿Cómo imprimir una lista más agradable?

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

evenNicerPrint(foolist) 

resultado deseado:

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

gracias!

+1

primer lugar, no es una buena idea usar dict como nombre de variable En segundo lugar, lo que están tratando para imprimir aquí hay una lista, un dict utiliza {} y: para separar las claves y los valores –

+3

-1: El título de la pregunta dice "lista" - una duplicación completa. La pregunta dice "dict". El código de muestra es una lista: una duplicación completa. ¿Quieres que la lista se convierta en un dict y se imprima? Si es así, corrige la pregunta para describir lo que * realmente * quieres. –

+0

He corregido la descripción y el código de muestra según las recomendaciones. El título y la descripción ahora reflejan mi objetivo. Gracias por las correcciones. –

Respuesta

10

simple:

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

que no producirá la salida (los datos están en orden principal de la columna). – falstro

+0

Gracias, corregido :) –

+0

Acepto esto como la respuesta porque lo hice funcionar de manera confiable en el menor tiempo posible, y puedo entenderlo. Si bien sería mejor tener informes dinámicos de columnas múltiples como algunas de las otras respuestas, no podría hacer que funcionen de manera confiable (probablemente porque no he podido seguir la lógica en ellos) - a veces los elementos se eliminan de la enumere a medida que crece/se reduce, o ya no se alinean en columnas. Gracias Aaron! –

3

Si los datos están en el formato que usted ha proporcionado, que es un poco más de trabajo


>>> 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 para una solución de una sola línea – Mizipzor

5

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

Una solución general, se ocupa de cualquier número de columnas y listas impares. Los caracteres de tabulación separan columnas, usando expresiones de generador para ahorrar espacio.

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

orden horizontal, probablemente esto no es lo que quiere –

5

La forma Aaron ha hecho que puede trabajar con más de dos columnas


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

si la longitud de l no es un múltiplo de cols, puede rellenar agregando algunas cadenas vacías al final –

-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

esta pregunta utiliza el mismo método en la respuesta por @Aaron Digulla, con una sintaxis un poco más Pythonic. Podría hacer que algunas de las respuestas anteriores sean más fáciles de entender.

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

Esto se puede adaptar fácilmente a cualquier número de columnas o columnas variables, lo que conduciría a algo así como la respuesta por @gnibbler. El espaciado se puede ajustar para el ancho de la pantalla.


Actualización: Explicación solicitada.

Indexing

foolist[::3] selecciona cada tercer elemento de foolist. foolist[1::3] selecciona cada tercer elemento, comenzando en el segundo elemento ('1' porque python usa indexación cero).

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

postal

listas Comprimir (u otros iterables) genera tuplas de los elementos de las listas. Por ejemplo:

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

juntos

Poner estas ideas juntas obtenemos nuestra solución:

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

Aquí primero generamos tres "rebanadas" de foolist, cada uno en un índice por cada tercio -elemento y compensación por uno. Individualmente, cada uno de ellos contiene solo un tercio de la lista.Ahora cuando creamos zip estas divisiones e iteramos, cada iteración nos da tres elementos de foolist.

que es lo que queríamos:

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] 

En lugar de:

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

¿Puede explicar en qué consiste? pasando en zip (tonto ...)? –

+0

Explicación agregada según lo solicitado por @matt wilkie – Aman

+0

Excelente explicación, gracias! –

0

Encontrado esta cuestión como casi la misma tarea conocido. Y he creado la función para imprimir la lista en varias columnas con el número de columnas como parámetro. Tal vez no tan elegante como soluciones de una sola línea, pero podría ser útil para alguien.

Sin embargo, maneja listas incompletas, por ejemplo: puede imprimir la lista de 11 en 3 filas.

Función dividido para una mejor legibilidad:

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

y la parte llamada:

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

Aquí está mi solución. (Copy in GitHub gist)

Toma el ancho del terminal como entrada y muestra solo las columnas que caben en él.

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

Aquí hay una solución en python 3.4 que detecta automáticamente el ancho del terminal y lo tiene en cuenta. Probado en Linux y 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

Inspirado por la respuesta de 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 

Resultados (el segundo satisface su petición):

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

Sugerir str (c) .ljust, porque c.ljust no funcionó con mis elementos de lista. En la 3 ª línea, y también len (str (elemento)), para precalcular las longitudes de la misma manera. –

+0

@ErikKruus gracias, he hecho una edición en ese sentido. Ahora estoy creando una nueva lista del obj entrante que se convierte en cadenas. Evita la necesidad de múltiples str() y protege el objeto entrante de ser editado. – ozagon

1

que se extienden una solución n columna para @Aman 's respuesta

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

Prueba

Configure el prueba con longitudes de cuerdas aleatorias

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

que devuelve

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

Es útil para permitir columnas irregulares, sin tener que saber de antemano el número de columnas que puede encajar:

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

Para su ejemplo:

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

Aquí está el código. Tenga en cuenta que también maneja las palabras con los códigos de color ANSI (como en el paquete colorama) - no arruinarán el ancho de las columnas.

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

¿Qué tal algo así?

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) 

salida

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

o

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