Форматирование списка текста в столбцы

Я пытаюсь вывести список строковых значений в формат 2 столбца. Стандартный способ создания списка строк в "обычный текст" осуществляется с помощью метода string.join. Однако он принимает только 2 аргумента, поэтому я могу сделать только один столбец, используя "\n". Я думал, что попытка создать цикл, который просто добавит вкладку между столбцами, сделает это, но логика не работает правильно.

Я нашел страницу ActiveState, которая имеет довольно сложный способ сделать это, но это с 4 лет назад. Есть ли простой способ сделать это сейчас?


Изменить. Вот список, который я хочу использовать.

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

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

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

Ответы

Ответ 1

Два столбца, разделенные вкладками, соединены в строки. Посмотрите в itertools для эквивалентов итератора, чтобы получить экономически эффективное решение.

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

Упс... поймал С.Лотт (спасибо).

Более общее решение, обрабатывает любое количество столбцов и нечетных списков. Немного изменен из S.lott, используя генераторы для экономии места.

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

Ответ 3

Это длинный, поэтому я разбиваю его на две части.

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 )

Это, очевидно, можно сделать как одно выражение loooong.

Это работает и для нечетного количества навыков.

Ответ 4

Вот расширение решения, предоставляемое gimel, которое позволяет печатать столбцы с одинаковой разницей.

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)

который возвращает что-то вроде этого

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

Ответ 5

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

Не так гибко, как решение ActiveState, но короче: -)

Ответ 6

Функция format_columns должна делать то, что вы хотите:

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

Это предполагает, что у вас есть Python с доступными генераторами.

Ответ 7

Я думаю, что многие из этих решений объединяют две отдельные вещи в одну.

Вы хотите:

  • может заставить строку быть определенной шириной
  • распечатать таблицу

Вот очень простой пример о том, как это сделать:

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