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

367

Я новичок в 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 с отступом и я пытался печатать как строки.

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

hjweide
источник
1
+1, я просто пытался сделать то же самое прошлой ночью. Вы просто пытаетесь печатать в командной строке или используете модуль GUI?
HellaMad
Просто печать в командной строке. Тем не менее, он должен пройти модульный тест, поэтому форматирование здесь очень важно.
hjweide
3
возможный дубликат печати табличных данных в Python
Чиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
1
Возможный дубликат Python: довольно печатные таблицы ascii?
Мартин Тома
Обратите внимание, что требование здесь довольно специализированное, поскольку метки строк и столбцов одинаковы. Так что для этого конкретного случая специальный код является хорошим примером того, как легко это может быть. Но другие решения здесь могут быть лучше для более общего отображения таблиц.
nealmcb

Ответы:

189

Некоторый специальный код для 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()и от формата спецификации мини-языка .

Свен Марнах
источник
3
Если вы используете python2.6, не забудьте добавить индекс team_list к row_format: row_format = "{0:> 15} {1:> 15} {2:> 15}"
Луис Муньос,
1
Если данные в теле больше, чем заголовки, вы можете установить ширину столбца на основе первой строки данных. для t в данных [0]: row_format + = "{: <" + str (len (t) +5) + "}"
моргантащук
588

Для этого есть несколько легких и полезных пакетов Python:

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 вы можете контролировать горизонтальное / вертикальное выравнивание, стиль границы и типы данных.

4. termtables : https://github.com/nschloe/termtables

import termtables as tt

string = tt.to_string(
    [["Alice", 24], ["Bob", 19]],
    header=["Name", "Age"],
    style=tt.styles.ascii_thin_double,
    # alignment="ll",
    # padding=(0, 1),
)
print(string)
+-------+-----+
| Name  | Age |
+=======+=====+
| Alice | 24  |
+-------+-----+
| Bob   | 19  |
+-------+-----+

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

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

  • terminaltables Легко рисовать таблицы в терминальных / консольных приложениях из списка списков строк. Поддерживает многострочные строки.
  • asciitable Asciitable может читать и записывать широкий спектр форматов таблиц ASCII через встроенные классы расширений Reader.
иман
источник
13
Я нашел, что tabulate - очень полезный инструмент для создания ориентированных на данные инструментов CLI. Это, в сочетании с кликом (pip install click), и вы получите настоящее рагу.
alexbw
4
Это замечательно, спасибо. Лично, кого бы вы предпочли среди этих трех?
Джим Рейнор
Блестящий ответ! PrettyTable очень хорош - идеальный баланс между двумя другими вариантами.
Edesz
2
Terminaltables хорош для китайского, может быть, других неанглийских языков
thinker3
5
Я только что поиграл с основными пакетами и IMO "beautifultable" - лучший, поддерживаемый, хороший API & doco, поддержка цветных. "texttable" - хороший, поддерживаемый, хороший API, но использование цветного использования выбрасывает таблицы из выравнивания. "Terminaltables" - хорошо, документируйте только через примеры кода. «PrettyTable» - хорошо, но старые «заголовки» таблиц у меня не работают. "Tabulate" - хорошо, но coalignключевое слово выравнивания столбцов не поддерживается в официальной версии Pypi. «tableprint» - средний, API сложный, мало распространенных примеров использования.
Абулька
79
>>> 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        
JFS
источник
6
Спасибо, это выглядит многообещающе, но я пытаюсь сделать это, не используя больше импортированных библиотек, чем это абсолютно необходимо.
hjweide
26
Использование pandas только для форматирования вывода похоже на Overkill (заглавная O предназначена).
Нильс Бом
66
@NielsBom: приходите к выходному форматированию, оставайтесь для анализа данных и моделирования :)
JFS
30
@JFSebastian для меня это было больше похоже на «приходите к выходному форматированию, убегайте с криком из-за 10-минутной тупой компиляции, из-за которой мой компьютер звучал как фен» ;-)
Niels Bom
4
@NielsBom: pip install numpyтеперь использует бинарные колеса на большинстве платформ (без компиляции) . Очевидно, что другие варианты двоичной установки были доступны еще до этого.
JFS
68

Python на самом деле делает это довольно легко.

Что-то вроде

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.

Остин
источник
Этот ответ помог мне найти то, что я искал! Для Python 3 я в конечном итоге использовал его, например, print('%-20.2f' % position['deg'], '%-17.2f' % position['v2'])где .2указывается точность поплавкаf
Росс
27

Обновление ответа Свена Марнача для работы в Python 3.4:

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))
SmrtGrunt ушел, потому что Моника
источник
9

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

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
campkeith
источник
9

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

Основное использование

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

Затем импортируйте это:

import TableIt

Затем составьте список списков, где каждый внутренний список представляет собой строку:

table = [
    [4, 3, "Hi"],
    [2, 1, 808890312093],
    [5, "Hi", "Bye"]
]

Тогда все, что вам нужно сделать, это напечатать это:

TableIt.printTable(table)

Это результат, который вы получаете:

+--------------------------------------------+
| 4            | 3            | Hi           |
| 2            | 1            | 808890312093 |
| 5            | Hi           | Bye          |
+--------------------------------------------+

Имена полей

Вы можете использовать имена полей, если хотите ( если вы не используете имена полей, вам не нужно говорить useFieldNames = False, потому что оно установлено по умолчанию ):


TableIt.printTable(table, useFieldNames=True)

От этого вы получите:

+--------------------------------------------+
| 4            | 3            | Hi           |
+--------------+--------------+--------------+
| 2            | 1            | 808890312093 |
| 5            | Hi           | Bye          |
+--------------------------------------------+

Есть и другие применения, например, вы можете сделать это:

import TableIt

myList = [
    ["Name", "Email"],
    ["Richard", "richard@fakeemail.com"],
    ["Tasha", "tash@fakeemail.com"]
]

TableIt.print(myList, useFieldNames=True)

От этого:

+-----------------------------------------------+
| Name                  | Email                 |
+-----------------------+-----------------------+
| Richard               | richard@fakeemail.com |
| Tasha                 | tash@fakeemail.com    |
+-----------------------------------------------+

Или вы могли бы сделать:

import TableIt

myList = [
    ["", "a", "b"],
    ["x", "a + x", "a + b"],
    ["z", "a + z", "z + b"]
]

TableIt.printTable(myList, useFieldNames=True)

И из этого вы получаете:

+-----------------------+
|       | a     | b     |
+-------+-------+-------+
| x     | a + x | a + b |
| z     | a + z | z + b |
+-----------------------+

Цвета

Вы также можете использовать цвета.

Вы используете цвета, используя опцию цвета ( по умолчанию он установлен на Нет ) и указания значений RGB.

Используя пример сверху:

import TableIt

myList = [
    ["", "a", "b"],
    ["x", "a + x", "a + b"],
    ["z", "a + z", "z + b"]
]

TableIt.printTable(myList, useFieldNames=True, color=(26, 156, 171))

Тогда вы получите:

введите описание изображения здесь

Обратите внимание, что печать цветов может не работать, но она работает точно так же, как и в других библиотеках, которые печатают цветной текст. Я проверил, и каждый цвет работает. Синий также не испорчен, как при использовании по умолчанию34m escape-последовательность ANSI (если вы не знаете, что это такое, это не имеет значения). В любом случае, все это происходит из-за того, что каждый цвет является значением RGB, а не системным значением по умолчанию.

Больше информации

Для получения дополнительной информации проверьте страницу GitHub

BeastCoder
источник
TableIt действительно хороший инструмент. Простой, но мощный. Единственный недостаток, который я считаю, это то, что TableIt не объявил
ЛИЦЕНЗИЮ
@Endle_Zhenbo Привет! Большое спасибо, я буду работать над этим как можно скорее!
BeastCoder
1
@Endle_Zhenbo, я знаю, что это было давно, но я наконец-то разместил лицензию на проект.
BeastCoder
8

Я думаю, это то, что вы ищете.

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

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

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

Из строки 53 с:

 print >> out, row[0].rjust(col_paddings[0] + 1),
Богдан
источник
7

Чистый Питон 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
Специалист по данным
источник
5

Простой способ сделать это - перебрать все столбцы, измерить их ширину, создать 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
Эмиль Стенстрём
источник
3

Следующая функция создаст запрошенную таблицу (с numpy или без) с помощью Python 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 .

Ссылки:

Diomedea
источник
2

Я попытался бы пройтись по списку и использовать форматтер CSV для представления нужных вам данных.

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

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

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

Джеффри Кевин Прай
источник
Это была моя первоначальная попытка, возможно, это можно сделать, но, похоже, много усилий для того, чтобы добиться идеального форматирования.
hjweide
2

Я нашел это просто в поисках способа вывода простых столбцов. Если вам просто нужны столбцы без суеты , то вы можете использовать это:

print("Titlex\tTitley\tTitlez")
for x, y, z in data:
    print(x, "\t", y, "\t", z)

РЕДАКТИРОВАТЬ: Я пытался быть как можно проще, и поэтому сделал некоторые вещи вручную, вместо того, чтобы использовать список команд. Чтобы обобщить актуальный вопрос ОП:

#Column headers
print("", end="\t")
for team in teams_list:
    print(" ", team, end="")
print()
# rows
for team, row in enumerate(data):
    teamlabel = teams_list[team]
    while len(teamlabel) < 9:
        teamlabel = " " + teamlabel
    print(teamlabel, end="\t")
    for entry in row:
        print(entry, end="\t")
    print()

Выходы:

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

Но это больше не кажется более простым, чем другие ответы, возможно, с преимуществом, которое не требует больше импорта. Но ответ @ campkeith уже встречал это и является более надежным, поскольку он может обрабатывать более разнообразные длины меток.

pr3sidentspence
источник
1
это обсуждается на meta meta.stackoverflow.com/questions/381571/…
Феликс Ганьон-Гренье