Печать списков в виде табличных данных

Я новичок в Python, и сейчас я пытаюсь красиво отформатировать свои данные для вывода на печать.

У меня есть один список, который используется для двух заголовков, и матрица, которая должна быть содержимым таблицы. Вот так:

teams_list = ["Man Utd", "Man City", "T Hotspur"]
data = np.array([[1, 2, 1],
                 [0, 1, 0],
                 [2, 4, 2]])

Обратите внимание, что названия заголовков не обязательно имеют одинаковую длину. Тем не менее, записи данных являются целыми числами.

Теперь я хочу представить это в виде таблицы, примерно так:

            Man Utd   Man City   T Hotspur
  Man Utd         1          0           0
 Man City         1          1           0
T Hotspur         0          1           2

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

Я уверен, что должен быть очень простой способ сделать это, но я, вероятно, скучаю по нему из-за отсутствия опыта.

 nealmcb14 февр. 2017 г., 16:36
Обратите внимание, что требование здесь довольно специализированное, поскольку метки строк и столбцов одинаковы. Так что для этого конкретного случая специальный код является хорошим примером того, как легко это может быть. Но другие решения здесь могут быть лучше для более общего отображения таблиц.
 DC_02 мар. 2012 г., 16:36
+1, я просто пытался сделать то же самое прошлой ночью. Вы просто пытаетесь печатать в командной строке или используете модуль GUI?
 hjweide02 мар. 2012 г., 16:38
Просто печать в командной строке. Тем не менее, он должен пройти модульный тест, поэтому форматирование здесь очень важно.
 Martin Thoma24 июл. 2016 г., 11:39

Ответы на вопрос(12)

Решение Вопроса

Некоторый специальный код для Python 2.7:

row_format ="{:>15}" * (len(teams_list) + 1)
print row_format.format("", *teams_list)
for team, row in zip(teams_list, data):
    print row_format.format(team, *row)

Это зависит отstr.format() иСпецификация формата Mini-Language.

 SmrtGrunt02 февр. 2017 г., 23:18
Я обновил это для Python 3 в ответе ниже.
 ademar11119023 июн. 2015 г., 23:43
u '{:> 15}' для юникодов
 Luis Muñoz13 февр. 2014 г., 20:09
При использовании python2.6 не забудьте добавить индекс team_list в row_format: row_format = "{0:> 15} {1:> 15} {2:> 15}"
 morgantaschuk23 февр. 2016 г., 17:42
Если данные в теле больше, чем заголовки, вы можете установить ширину столбца на основе первой строки данных. для t в данных [0]: row_format + = "{: <" + str (len (t) +5) + "}"

Чистый Питон 3

def print_table(data, cols, wide):
    '''Prints formatted data on columns of given width.'''
    n, r = divmod(len(data), cols)
    pat = '{{:{}}}'.format(wide)
    line = '\n'.join(pat * cols for _ in range(n))
    last_line = pat * r
    print(line.format(*data))
    print(last_line.format(*data[n*cols:]))

data = [str(i) for i in range(27)]
print_table(data, 6, 12)

Будет печатать

0           1           2           3           4           5           
6           7           8           9           10          11          
12          13          14          15          16          17          
18          19          20          21          22          23          
24          25          26

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

def format_matrix(header, matrix,
                  top_format, left_format, cell_format, row_delim, col_delim):
    table = [[''] + header] + [[name] + row for name, row in zip(header, matrix)]
    table_format = [['{:^{}}'] + len(header) * [top_format]] \
                 + len(matrix) * [[left_format] + len(header) * [cell_format]]
    col_widths = [max(
                      len(format.format(cell, 0))
                      for format, cell in zip(col_format, col))
                  for col_format, col in zip(zip(*table_format), zip(*table))]
    return row_delim.join(
               col_delim.join(
                   format.format(cell, width)
                   for format, cell, width in zip(row_format, row, col_widths))
               for row_format, row in zip(table_format, table))

print format_matrix(['Man Utd', 'Man City', 'T Hotspur', 'Really Long Column'],
                    [[1, 2, 1, -1], [0, 1, 0, 5], [2, 4, 2, 2], [0, 1, 0, 6]],
                    '{:^{}}', '{:<{}}', '{:>{}.3f}', '\n', ' | ')

Вот вывод:

                   | Man Utd | Man City | T Hotspur | Really Long Column
Man Utd            |   1.000 |    2.000 |     1.000 |             -1.000
Man City           |   0.000 |    1.000 |     0.000 |              5.000
T Hotspur          |   2.000 |    4.000 |     2.000 |              2.000
Really Long Column |   0.000 |    1.000 |     0.000 |              6.000

это это то, что вы ищете.

Это простой модуль, который просто вычисляет максимальную требуемую ширину для записей таблицы, а затем просто используетrjust а такжеljust сделать красивую печать данных.

Если вы хотите, чтобы ваш левый заголовок был выровнен по правому краю, просто измените этот вызов:

 print >> out, row[0].ljust(col_paddings[0] + 1),

Из строки 53 с:

 print >> out, row[0].rjust(col_paddings[0] + 1),

Что-то вроде

for i in range(10):
    print '%-12i%-12i' % (10 ** i, 20 ** i)

будет иметь выход

1           1           
10          20          
100         400         
1000        8000        
10000       160000      
100000      3200000     
1000000     64000000    
10000000    1280000000  
100000000   25600000000
1000000000  512000000000

% Внутри строки по сути является escape-символом, а следующие за ним символы указывают Python, какой формат должны иметь данные. % Снаружи и после строки сообщает Python, что вы намерены использовать предыдущую строку в качестве строки формата и что следующие данные должны быть помещены в указанный формат.

В этом случае я использовал «% -12i» дважды. Чтобы разбить каждую часть:

'-' (left align)
'12' (how much space to be given to this part of the output)
'i' (we are printing an integer)

Из документов:https://docs.python.org/2/library/stdtypes.html#string-formatting

 hzitoun29 апр. 2018 г., 19:23
Спасибо! Просто и очень эффективно!
>>> import pandas
>>> pandas.DataFrame(data, teams_list, teams_list)
           Man Utd  Man City  T Hotspur
Man Utd    1        2         1        
Man City   0        1         0        
T Hotspur  2        4         2        
 Niels Bom07 нояб. 2013 г., 10:13
@ J.F.Sebastian для меня это было больше похоже на «приходите к выходному форматированию, убегайте с криком из-за 10-минутной тупой компиляции, из-за которой мой компьютер звучал как фен» ;-)
 jfs06 нояб. 2013 г., 19:08
@NielsBom: приходите к выходному форматированию, оставайтесь для анализа данных и моделирования :)
 jfs04 авг. 2016 г., 13:54
@NielsBom:pip install numpy теперь использует бинарные колеса на большинстве платформ (без компиляции), Очевидно, что другие варианты двоичной установки были доступны еще до этого.
 hjweide02 мар. 2012 г., 16:50
Спасибо, это выглядит многообещающе, но я пытаюсь сделать это, не используя больше импортированных библиотек, чем это абсолютно необходимо.
 Niels Bom06 нояб. 2013 г., 16:56
Использование pandas только для форматирования вывода похоже на Overkill (заглавная O предназначена).

on 3 (возможно, также Python 2). Я выбрал ширину каждого столбца, соответствующую ширине самого длинного имени команды. Вы можете изменить его, если хотите использовать длину имени команды для каждого столбца, но это будет более сложным.

Примечание: для прямого эквивалента в Python 2 вы можете заменитьzip с участиемizip из itertools.

def print_results_table(data, teams_list):
    str_l = max(len(t) for t in teams_list)
    print(" ".join(['{:>{length}s}'.format(t, length = str_l) for t in [" "] + teams_list]))
    for t, row in zip(teams_list, data):
        print(" ".join(['{:>{length}s}'.format(str(x), length = str_l) for x in [t] + row]))

teams_list = ["Man Utd", "Man City", "T Hotspur"]
data = [[1, 2, 1],
        [0, 1, 0],
        [2, 4, 2]]

print_results_table(data, teams_list)

Это приведет к следующей таблице:

            Man Utd  Man City T Hotspur
  Man Utd         1         2         1
 Man City         0         1         0
T Hotspur         2         4         2

Если вы хотите иметь вертикальные разделители строк, вы можете заменить" ".join с участием" | ".join.

Рекомендации:

много о форматированииhttps://pyformat.info/ (старые и новые стили форматирования)официальный учебник по Python (довольно хорошо) -https://docs.python.org/3/tutorial/inputoutput.html#the-string-format-methodофициальная информация о Python (может быть трудно читать) -https://docs.python.org/3/library/string.html#string-formattingЕще один ресурс -https://www.python-course.eu/python3_formatted_output.php

дставления нужных вам данных.

Вы можете указать табуляцию, запятую или любой другой символ в качестве разделителя.

В противном случае просто переберите список и напечатайте «\ t» после каждого элемента

http://docs.python.org/library/csv.html

 hjweide02 мар. 2012 г., 16:51
Это была моя первоначальная попытка, возможно, это можно сделать, но, похоже, много усилий для того, чтобы добиться идеального форматирования.

1. табулировать: https://pypi.python.org/pypi/tabulate

>>> from tabulate import tabulate
>>> print tabulate([['Alice', 24], ['Bob', 19]], headers=['Name', 'Age'])
Name      Age
------  -----
Alice      24
Bob        19

В tabulate есть много опций для указания заголовков и формата таблицы.

>>> print tabulate([['Alice', 24], ['Bob', 19]], headers=['Name', 'Age'], tablefmt='orgtbl')
| Name   |   Age |
|--------+-------|
| Alice  |    24 |
| Bob    |    19 |

2. PrettyTable: https://pypi.python.org/pypi/PrettyTable

>>> from prettytable import PrettyTable
>>> t = PrettyTable(['Name', 'Age'])
>>> t.add_row(['Alice', 24])
>>> t.add_row(['Bob', 19])
>>> print t
+-------+-----+
|  Name | Age |
+-------+-----+
| Alice |  24 |
|  Bob  |  19 |
+-------+-----+

PrettyTable имеет опции для чтения данных из базы данных CSV, HTML, SQL. Также вы можете выбрать подмножество данных, отсортировать таблицу и изменить стили таблицы.

3. текстовый: https://pypi.python.org/pypi/texttable

>>> from texttable import Texttable
>>> t = Texttable()
>>> t.add_rows([['Name', 'Age'], ['Alice', 24], ['Bob', 19]])
>>> print t.draw()
+-------+-----+
| Name  | Age |
+=======+=====+
| Alice | 24  |
+-------+-----+
| Bob   | 19  |
+-------+-----+

с помощью texttable вы можете управлять горизонтальным / вертикальным выравниванием, стилем границ и типами данных.

Другие опции:

terminaltables Легко рисовать таблицы в терминальных / консольных приложениях из списка списков строк. Поддерживает многострочные строки.asciitable Asciitable может читать и записывать широкий спектр форматов таблиц ASCII через встроенные классы расширений Reader.
 Jim Raynor16 июн. 2015 г., 16:03
Это замечательно, спасибо. Лично, какой из них вы бы предпочли среди этих трех?
 alexbw23 нояб. 2014 г., 21:53
Я нашел, что tabulate - очень полезный инструмент для создания ориентированных на данные инструментов CLI. Это, в сочетании с кликом (pip install click), и вы получите настоящее рагу.
 Goosebumps11 окт. 2016 г., 10:26
Мне нравится метод добавления столбца в красивой таблице.
 metaphy04 июл. 2016 г., 01:32
Terminaltables хорош для китайского, может быть, других неанглийских языков
 edesz22 мая 2016 г., 02:14
Блестящий ответ! PrettyTable очень хорош - идеальный баланс между двумя другими вариантами.

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

Вот пример из Beautifultable'sдокументация

>>> from beautifultable import BeautifulTable
>>> table = BeautifulTable()
>>> table.column_headers = ["name", "rank", "gender"]
>>> table.append_row(["Jacob", 1, "boy"])
>>> table.append_row(["Isabella", 1, "girl"])
>>> table.append_row(["Ethan", 2, "boy"])
>>> table.append_row(["Sophia", 2, "girl"])
>>> table.append_row(["Michael", 3, "boy"])
>>> print(table)
+----------+------+--------+
|   name   | rank | gender |
+----------+------+--------+
|  Jacob   |  1   |  boy   |
+----------+------+--------+
| Isabella |  1   |  girl  |
+----------+------+--------+
|  Ethan   |  2   |  boy   |
+----------+------+--------+
|  Sophia  |  2   |  girl  |
+----------+------+--------+
| Michael  |  3   |  boy   |
+----------+------+--------+

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

table = [
    ["", "Man Utd", "Man City", "T Hotspur"],
    ["Man Utd", 1, 0, 0],
    ["Man City", 1, 1, 0],
    ["T Hotspur", 0, 1, 2],
]
def print_table(table):
    longest_cols = [
        (max([len(str(row[i])) for row in table]) + 3)
        for i in range(len(table[0]))
    ]
    row_format = "".join(["{:>" + str(longest_col) + "}" for longest_col in longest_cols])
    for row in table:
        print(row_format.format(*row))

Вы используете это так:

>>> print_table(table)

            Man Utd   Man City   T Hotspur
  Man Utd         1          0           0
 Man City         1          1           0
T Hotspur         0          1           2

row_format ="{:>15}" * (len(teams_list) + 1)
print(row_format.format("", *teams_list))
for team, row in zip(teams_list, data):
    print(row_format.format(team, *row))

Ваш ответ на вопрос