Распечатать список списков в аккуратных столбцах / таблица - PullRequest
2 голосов
/ 18 апреля 2020

У меня есть список списков со структурой [[s: str, s: str, s: str]], и внутри него может быть любое количество элементов (списков).

Я хочу напечатать это чисто в столбцах, например:

FirstFirst     FirstSecond    FirstThird
SecondFirst    SecondSecond   SecondThird
ThirdFirst     ThirdSecond    ThirdThird
foo            bar            foobar

Итак, несмотря на разную длину, каждый элемент в подсписках выровнен по левому краю в столбце.

Я уже пробовал очень сложные списки, такие как

lists = [['FirstFirst', 'FirstSecond', 'FirstThird'],
         ['SecondFirst', 'SecondSecond', 'SecondThird'],
         ['ThirdFirst', 'ThirdSecond', 'ThirdThird'],
         ['foo', 'bar', 'foobar']]

[print(f'{_[0]}{" " * (15 - len(_[0]))}{_[1]}{" " * (30 - len(_[0] + _[1] + " " * (15 - len(_[0]))))}{_[2]}') for _ in lists]

Хотя это работает, это очень брутфорс - я sh.

Что еще хуже, это понимание списков совсем не масштабируется. Если я хочу добавить еще одну строку к каждому элементу в подсписках, мне придется добавить гораздо больше к своему пониманию списка, чтобы все это продолжало работать. Кроме того, все срывается, если я хочу, чтобы два списка имели разную длину.

Какой лучший способ сделать это?

Ответы [ 2 ]

2 голосов
/ 18 апреля 2020

Использование списочного понимания для побочного эффекта - плохой стиль: вы создаете полный список (который занимает время и память), который впоследствии выбрасывается - используйте простые циклы.

Вам необходимо вычислить длину каждого слово (в каждом столбце). Получить максимальную длину ваших слов просто:

data = [['FirstFirst', 'FirstSecond', 'FirstThird'],
         ['SecondFirst', 'SecondSecond', 'SecondThird'],
         ['ThirdFirst', 'ThirdSecond', 'ThirdThird'],
         ['foo', 'verylongwordinsidehere', 'bar', ]]    # changed to a longer one


# get max word length
max_len = max(len(i) for j in data for i in j)

# do not use list comp for printing side effect - use a simple loop
for inner in data:
    for word in inner:
        print(f"{word:{max_len}}",end=" | ") # and format the length into it
    print()

, чтобы получить

FirstFirst             | FirstSecond            | FirstThird             | 
SecondFirst            | SecondSecond           | SecondThird            | 
ThirdFirst             | ThirdSecond            | ThirdThird             | 
foo                    | verylongwordinsidehere | bar                    | 

Это выглядит довольно уродливо, было бы лучше, если бы вы получили только максимальную длину для столбца imho:

# transpose the list, get the max of each column and store in as dict[column]=legnth
col_len = {i:max(map(len,inner)) for i,inner in enumerate(zip(*data))}

# print(col_len) # {0: 11, 1: 22, 2: 11}

# print using the column index from enumerate to lookup this columns lenght
for inner in data:
    for col,word in enumerate(inner):
        print(f"{word:{col_len[col]}}",end=" | ")
    print()

, чтобы получить вывод, скорректированный по ширине столбца:

FirstFirst  | FirstSecond            | FirstThird  | 
SecondFirst | SecondSecond           | SecondThird | 
ThirdFirst  | ThirdSecond            | ThirdThird  | 
foo         | verylongwordinsidehere | bar         | 

См.


Если вам нужно сделать его короче, вы можете использовать ' | '.join() для печати списков:

# do not use list comp for printing side effect - use a simple loop
for inner in data:
    print( ' | '.join( (f"{word:{max_len}}" for word in inner)))

Если вам нужно также распечатать неровные списки, zip () не подойдет - вы можете обойти это (исследование itertiols.zip_longest), но если вам это действительно нужно, задайте новый вопрос с данными для этого после того, как вы попытались что-то сделать, чтобы сделать то, что вам нужно.

2 голосов
/ 18 апреля 2020

Использование понимания:

# first map each string to formatted string with white space 
lists = [list(map(lambda item: f'{item:<20}', inner_list)) for inner_list in lists]
#then join them 
lists = [''.join(item) for item in lists]
print('\n'.join(lists))

Единственная проблема здесь в том, что 20 не может быть переменной, она должна быть жестко закодирована

...