2010-09-10 7 views
10

tengo datos (números) guardados en el formato siguiente (ejemplo):Alinea columnas de números (salida de impresión en formato de tabla)

234 127 34 23 45567 
23 12 4 4 45 
23456 2 1 444 567 
... 

¿Hay algún método pitón vías para alinear los números y obténgalos como

234 127 34 23 45567 
    23 12 4 4  45 
23456 2 1 444 567 

(No puedo predecir el tamaño de la columna).

+0

Es inviable para repetir una vez a través de los datos para determinar el tamaño máximo de la columna? – teukkam

+0

posible duplicado de [Python: tablas ascii de impresión bonita?] (Http://stackoverflow.com/questions/5909873/python-pretty-printing-ascii-tables) – ecatmur

+0

También es posible duplicar de [_¿Cómo puedo imprimir los parámetros de múltiples Python objetos en forma de tabla? _] (Http://stackoverflow.com/questions/12503655/how-do-i-print-parameters-of-multiple-python-objects-in-table-form) – martineau

Respuesta

12

Aquí es un ejemplo simple, autónomo que muestra cómo dar formato ancho de las columnas variables:

data = '''\ 
234 127 34 23 45567 
23 12 4 4 45 
23456 2 1 444 567''' 

# Split input data by row and then on spaces 
rows = [ line.strip().split(' ') for line in data.split('\n') ] 

# Reorganize data by columns 
cols = zip(*rows) 

# Compute column widths by taking maximum length of values per column 
col_widths = [ max(len(value) for value in col) for col in cols ] 

# Create a suitable format string 
format = ' '.join(['%%%ds' % width for width in col_widths ]) 

# Print each row using the computed format 
for row in rows: 
    print format % tuple(row) 

que SALIDAS:

234 127 34 23 45567 
    23 12 4 4 45 
23456 2 1 444 567 
+0

Gracias por esto.FWIW Hice las columnas justificadas a la izquierda generando la cadena de formato con ''%% -% ds'' –

+0

Aquí está la parte relevante con los formatos de estilo nuevo, alineado a la izquierda: fmt =' '.join ([' { {: <{}}}. formato (ancho) para el ancho en col_widths]) para filas en filas: print fmt.format (* row) – mueslo

7

necesita alguna manera de encontrar el tamaño de la columna, tal vez mediante la lectura de todos los datos y la búsqueda de la máxima anchura.

>>> line='234 127 34 23 45567' 
>>> line.split() 
['234', '127', '34', '23', '45567'] 
>>> max(map(len, line.split())) 
5 

Repita en todas las líneas, para buscar el tamaño de columna (por ejemplo, 5). La construcción de una línea formateada con percent formatting es sencilla.

>>> colsize = 5 
>>> ' '.join(('%*s' % (colsize, i) for i in line.split())) 
' 234 127 34 23 45567' 
>>> 
+0

No sabía sobre '% * s'. ¡Buen consejo! –

+0

El problema es que estos números se conectan en línea y no sé cuántas filas. Para hacerlo más legible, me gustaría alinearlos. Eso es. – przemol

+1

Si no puede calcular el ancho máximo, solo use una buena estimación, p. 10. – gimel

4
#!/usr/bin/env python 

class ALIGN: 
    LEFT, RIGHT = '-', '' 

class Column(list): 
    def __init__(self, name, data, align=ALIGN.RIGHT): 
     list.__init__(self, data) 
     self.name = name 
     width = max(len(str(x)) for x in data + [name]) 
     self.format = ' %%%s%ds ' % (align, width) 

class Table: 
    def __init__(self, *columns): 
     self.columns = columns 
     self.length = max(len(x) for x in columns) 
    def get_row(self, i=None): 
     for x in self.columns: 
      if i is None: 
       yield x.format % x.name 
      else: 
       yield x.format % x[i] 
    def get_rows(self): 
     yield ' '.join(self.get_row(None)) 
     for i in range(0, self.length): 
      yield ' '.join(self.get_row(i)) 

    def __str__(self): 
     return '\n'.join(self.get_rows()) 

Para su ejemplo:

if __name__ == '__main__': 
    print Table(
     Column("", [234, 32, 23456]), 
     Column("", [127, 12, 2]), 
     Column("", [34, 4, 1]), 
     Column("", [23, 4, 444]), 
     Column("", [45567, 45, 567]) 
    ) 

Será rendimiento:

234 127 34 23 45567 
    32 12 4  4  45 
23456  2 1 444  567 

Adaptado de http://code.activestate.com/recipes/577202-render-tables-for-text-interface/

+2

Eso es increíblemente pesado a la vista de algunas otras soluciones. ¿Cuál es el beneficio de cocinar clases para manejar esto? – aaronasterling

+0

Pero esto es mucho más legible y elegante, ¿no crees? – Yuval

2
>>> rows = """234 127 34 23 45567 
... 23 12 4 4 45 
... 23456 2 1 444 567""" 

convertir primero las filas en una matriz 2D (lista de listas)

>>> arr=[x.split() for x in rows.split("\n")] 

ahora calcular el espacio necesitará cada campo para encajar en

>>> widths = [max(map(len,(f[i] for f in tab))) for i in range(len(arr[0]))] 

y la almohadilla de cada elemento para encajar en ese espacio

>>> [[k.rjust(widths[i]) for i,k in enumerate(j)] for j in arr] 
[[' 234', '127', '34', ' 23', '45567'], [' 23', ' 12', ' 4', ' 4', ' 45'], ['23456', ' 2', ' 1', '444', ' 567']] 

finalmente unirse a la matriz vuelta a una cadena

>>> print "\n".join(" ".join(k.rjust(widths[i]) for i,k in enumerate(j)) for j in arr) 
    234 127 34 23 45567 
    23 12 4 4  45 
23456 2 1 444 567 
1

Entero en frente de la d es en qué columna comenzarán los números enteros después del número anterior de para que pueda alinearlos de la manera que considere adecuada

print("{0:4d} {1:4d} {2:4d} {3:4d} {4:4d}".format(234, 127, 34, 23, 45567))

repita si es necesario

0

respuesta de Kevin Jacobs modificado para permitir a variable number of integers on each row:

def align(data, delimiter = '\t', is_left_align = True): 
    rows = [row.strip().split(delimiter) for row in data.split('\n')] 
    cols = map(lambda *row: [str(field) or '' for field in row], *rows) 
    widths = [max(len(field) for field in col) for col in cols] 
    format = ['%%%s%ds' % ('-' if is_left_align else '', width) for width in widths] 
    return '\n'.join([delimiter.join(format[:len(row)]) % tuple(row) for row in rows]) 

data = '''\ 
234 127 34 23 45567 
23 12 4 4 45 
23456 2 1 444 567''' 
print(align(data, ' ', False))