2008-10-05 14 views
16

Estoy tratando de generar una lista de valores de cadena en un formato de 2 columnas. La forma estándar de hacer una lista de cadenas en "texto normal" es usando el método string.join. Sin embargo, solo se necesitan 2 argumentos, así que solo puedo hacer una sola columna con "\ n". Pensé que intentar hacer un ciclo que simplemente agregara una pestaña entre columnas lo haría, pero la lógica no funcionaba correctamente.Dar formato a una lista de texto en las columnas

Encontré un ActiveState page que tiene una forma bastante complicada de hacerlo, pero es de hace 4 años. ¿Hay alguna manera fácil de hacerlo hoy en día?


Editar Aquí está la lista que quiero usar.

skills_defs = ["ACM:Aircraft Mechanic", "BC:Body Combat", "BIO:Biology", 
    "CBE:Combat Engineer", "CHM:Chemistry", "CMP:Computers", 
    "CRM:Combat Rifeman", "CVE:Civil Engineer", "DIS:Disguise", 
    "ELC:Electronics","EQ:Equestrian", "FO:Forward Observer", 
    "FOR:Forage", "FRG:Forgery", "FRM:Farming", "FSH:Fishing", 
    "GEO:Geology", "GS:Gunsmith", "HW:Heavy Weapons", "IF:Indirect Fire", 
    "INS:Instruction", "INT:Interrogation", "JP:Jet Pilot", "LB:Longbow", 
    "LAP:Light Aircraft Pilot", "LCG:Large Caliber Gun", "LNG:Language", 
    "LP:Lockpick", "MC:Melee Combat", "MCY:Motorcycle", "MEC:Mechanic", 
    "MED:Medical", "MET:Meterology", "MNE:Mining Engineer", 
    "MTL:Metallurgy", "MTN:Mountaineering", "NWH:Nuclear Warhead", 
    "PAR:Parachute", "PST:Pistol", "RCN:Recon", "RWP:Rotary Wing Pilot", 
    "SBH:Small Boat Handling","SCD:Scuba Diving", "SCR:Scrounging", 
    "SWM:Swimming", "TW:Thrown Weapon", "TVD:Tracked Vehicle Driver", 
    "WVD:Wheeled Vehicle Driver"] 

Solo quiero mostrar esta lista en un formato simple de 2 columnas para reducir el espacio. Idealmente, debería haber una cantidad estándar de espacio entre las columnas, pero puedo trabajar con ella.

ACM:Aircraft Mechanic  BC:Body Combat 
BIO:Biology   CBE:Combat Engineer 
CHM:Chemistry  CMP:Computers 
CRM:Combat Rifeman  CVE:Civil Engineer 
DIS:Disguise   ELC:Electronics 
EQ:Equestrian   FO:Forward Observer 
FOR:Forage   FRG:Forgery 
FRM:Farming    FSH:Fishing 
GEO:Geology    GS:Gunsmith 
HW:Heavy Weapons  IF:Indirect Fire 
INS:Instruction    INT:Interrogation 
JP:Jet Pilot   LB:Longbow 
LAP:Light Aircraft Pilot  LCG:Large Caliber Gun 
LNG:Language   LP:Lockpick 
MC:Melee Combat   MCY:Motorcycle 
MEC:Mechanic   MED:Medical 
MET:Meterology  MNE:Mining Engineer 
MTL:Metallurgy  MTN:Mountaineering 
NWH:Nuclear Warhead  PAR:Parachute 
PST:Pistol   RCN:Recon 
RWP:Rotary Wing Pilot  SBH:Small Boat Handling 
SCD:Scuba Diving  SCR:Scrounging 
SWM:Swimming  TW:Thrown Weapon 
TVD:Tracked Vehicle Driver WVD:Wheeled Vehicle Driver 
+0

¿Podría proporcionar el valor de entrada real y el formato de salida esperado? No está muy claro cómo es tu lista de entrada. –

Respuesta

0
data = [ ("1","2"),("3","4") ] 
print "\n".join(map("\t".join,data)) 

No tan flexible como la solución ActiveState, pero más corto :-)

+0

Esto no resuelve el problema, solo insertando tabuladores hará que las columnas se desarticulen cuando el contenido varíe (como en el ejemplo del OP de salida 'mala') – sidewinderguy

+1

@sidewinderguy pero es corto :-) –

+1

Indeed es asombrosamente corto :) – sidewinderguy

11

dos columnas, separadas por pestañas, unido en líneas. Mire en itertools para equivalentes de iterador, para lograr una solución que ahorre espacio.

import string 
def fmtpairs(mylist): 
    pairs = zip(mylist[::2],mylist[1::2]) 
    return '\n'.join('\t'.join(i) for i in pairs) 

print fmtpairs(list(string.ascii_uppercase)) 

A B 
C D 
E F 
G H 
I J 
... 

Oops ... got caught by S.Lott (gracias).

Una solución más general, maneja cualquier número de columnas y listas impares. Ligeramente modificado desde S.lott, usando generadores 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

Lamentablemente, esto no funciona bien para un número impar de elementos. –

+0

¡La segunda parte de esto es genial! – Richard

3

Es largo, así que lo dividiré en dos partes.

def columns(skills_defs, cols=2): 
    pairs = [ "\t".join(skills_defs[i:i+cols]) for i in range(0,len(skills_defs),cols) ] 
    return "\n".join(pairs) 

Puede, obviamente, hacerse como una sola declaración loooong.

Esto también funciona para un número impar de habilidades.

+0

Guau, esto es perfecto. – Richard

0

La función format_columns debe hacer lo que quiera:

from __future__ import generators 
try: import itertools 
except ImportError: mymap, myzip= map, zip 
else: mymap, myzip= itertools.imap, itertools.izip 

def format_columns(string_list, columns, separator=" "): 
    "Produce equal-width columns from string_list" 
    sublists= [] 

    # empty_str based on item 0 of string_list 
    try: 
     empty_str= type(string_list[0])() 
    except IndexError: # string_list is empty 
     return 

    # create a sublist for every column 
    for column in xrange(columns): 
      sublists.append(string_list[column::columns]) 

    # find maximum length of a column 
    max_sublist_len= max(mymap(len, sublists)) 

    # make all columns same length 
    for sublist in sublists: 
     if len(sublist) < max_sublist_len: 
      sublist.append(empty_str) 

    # calculate a format string for the output lines 
    format_str= separator.join(
     "%%-%ds" % max(mymap(len, sublist)) 
     for sublist in sublists) 

    for line_items in myzip(*sublists): 
     yield format_str % line_items 

if __name__ == "__main__": 
    skills_defs = ["ACM:Aircraft Mechanic", "BC:Body Combat", "BIO:Biology", 
     "CBE:Combat Engineer", "CHM:Chemistry", "CMP:Computers", 
     "CRM:Combat Rifeman", "CVE:Civil Engineer", "DIS:Disguise", 
     "ELC:Electronics","EQ:Equestrian", "FO:Forward Observer", 
     "FOR:Forage", "FRG:Forgery", "FRM:Farming", "FSH:Fishing", 
     "GEO:Geology", "GS:Gunsmith", "HW:Heavy Weapons", "IF:Indirect Fire", 
     "INS:Instruction", "INT:Interrogation", "JP:Jet Pilot", "LB:Longbow", 
     "LAP:Light Aircraft Pilot", "LCG:Large Caliber Gun", "LNG:Language", 
     "LP:Lockpick", "MC:Melee Combat", "MCY:Motorcycle", "MEC:Mechanic", 
     "MED:Medical", "MET:Meterology", "MNE:Mining Engineer", 
     "MTL:Metallurgy", "MTN:Mountaineering", "NWH:Nuclear Warhead", 
     "PAR:Parachute", "PST:Pistol", "RCN:Recon", "RWP:Rotary Wing Pilot", 
     "SBH:Small Boat Handling","SCD:Scuba Diving", "SCR:Scrounging", 
     "SWM:Swimming", "TW:Thrown Weapon", "TVD:Tracked Vehicle Driver", 
     "WVD:Wheeled Vehicle Driver"] 

    for line in format_columns(skills_defs, 2): 
     print line 

Esto supone que tiene un pitón con los generadores disponibles.

3

Aquí es una extensión de la solución aportada por gimel, que permite imprimir columnas equidistantes.

def fmtcols(mylist, cols): 
    maxwidth = max(map(lambda x: len(x), mylist)) 
    justifyList = map(lambda x: x.ljust(maxwidth), mylist) 
    lines = (' '.join(justifyList[i:i+cols]) 
      for i in xrange(0,len(justifyList),cols)) 
    print "\n".join(lines) 

que devuelve algo como esto

ACM:Aircraft Mechanic BC:Body Combat
BIO:Biology CBE:Combat Engineer
CHM:Chemistry CMP:Computers
CRM:Combat Rifeman CVE:Civil Engineer
DIS:Disguise ELC:Electronics ... ... `

+0

consigo este error cuando intento el método en mi lista de cadenas:
'Rastreo (llamada más reciente pasado): Archivo "tars.py", línea 45, en fmtcols de impresión (puestos de trabajo, 3) Archivo "tars.py", línea 10, en fmtcols maxwidth = max (map (lambda x: len (x), mylist)) Archivo "tars.py", línea 10, en maxwidth = max (mapa (lambda x: len (x), mylist)) TypeError: objeto de tipo 'int' no tiene len() ' – YouHaveaBigEgo

0

creo que muchas de estas soluciones están fusionando dos separar cosas int o uno

Usted quiere:

  1. ser capaz de forzar una cadena a ser una cierta anchura
  2. impresión de una mesa

Es una toma muy sencilla sobre cómo hacer esto aquí:

import sys 

skills_defs = ["ACM:Aircraft Mechanic", "BC:Body Combat", "BIO:Biology", 
"CBE:Combat Engineer", "CHM:Chemistry", "CMP:Computers", 
"CRM:Combat Rifeman", "CVE:Civil Engineer", "DIS:Disguise", 
"ELC:Electronics","EQ:Equestrian", "FO:Forward Observer", 
"FOR:Forage", "FRG:Forgery", "FRM:Farming", "FSH:Fishing", 
"GEO:Geology", "GS:Gunsmith", "HW:Heavy Weapons", "IF:Indirect Fire", 
"INS:Instruction", "INT:Interrogation", "JP:Jet Pilot", "LB:Longbow", 
"LAP:Light Aircraft Pilot", "LCG:Large Caliber Gun", "LNG:Language", 
"LP:Lockpick", "MC:Melee Combat", "MCY:Motorcycle", "MEC:Mechanic", 
"MED:Medical", "MET:Meterology", "MNE:Mining Engineer", 
"MTL:Metallurgy", "MTN:Mountaineering", "NWH:Nuclear Warhead", 
"PAR:Parachute", "PST:Pistol", "RCN:Recon", "RWP:Rotary Wing Pilot", 
"SBH:Small Boat Handling","SCD:Scuba Diving", "SCR:Scrounging", 
"SWM:Swimming", "TW:Thrown Weapon", "TVD:Tracked Vehicle Driver", 
"WVD:Wheeled Vehicle Driver"] 

# The only thing "colform" does is return a modified version of "txt" that is 
# ensured to be exactly "width" characters long. It truncates or adds spaces 
# on the end as needed. 
def colform(txt, width): 
    if len(txt) > width: 
     txt = txt[:width] 
    elif len(txt) < width: 
     txt = txt + (" " * (width - len(txt))) 
    return txt 

# Now that you have colform you can use it to print out columns any way you wish. 
# Here's one brain-dead way to print in two columns: 
for i in xrange(len(skills_defs)): 
    sys.stdout.write(colform(skills_defs[i], 30)) 
    if i % 2 == 1: 
     sys.stdout.write('\n') 
+0

Probado usando Python 2.7.6, funciona para mí :) – sidewinderguy

Cuestiones relacionadas