Pregunta Formatear una lista de texto en columnas


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 mediante el uso de string.join método. 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.

Encontré un Página ActiveState eso 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

16
2017-10-05 08:09


origen


Respuestas:


Dos columnas, separadas por pestañas, unidas en líneas. Pase a ver itertools para equivalentes de iterador, para lograr una solución eficiente en el uso del 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
...

Vaya ... me atrapó S.Lott (gracias).

Una solución más general, maneja cualquier cantidad de columnas y listas impares. Ligeramente modificado de 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)

11
2017-10-05 08:40



Esto funciona

it = iter(skills_defs)
for i in it:
    print('{:<60}{}'.format(i, next(it, "")))

Ver:  Ejemplos de formato de cadena


4
2017-10-04 06:34



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 )

Obviamente, se puede hacer como una sola declaración loooong.

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


3
2017-10-06 10:33



Aquí hay una extensión de la solución proporcionada por gimel, que permite imprimir columnas equiespaciadas.

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


3
2017-07-22 00:12



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

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


0
2017-10-05 08:22



los format_columns la función debe hacer lo que quieras:

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 tienes un Python con generadores disponibles.


0
2017-10-06 11:21



Creo que muchas de estas soluciones combinan dos cosas separadas en una sola.

Tú quieres:

  1. ser capaz de forzar una cuerda para que tenga un ancho determinado
  2. imprime una mesa

Aquí hay una idea muy simple sobre cómo hacer esto:

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
2017-11-19 21:30