Danh sách in dưới dạng dữ liệu dạng bảng


366

Tôi còn khá mới với Python và hiện tôi đang vật lộn với việc định dạng dữ liệu của mình một cách độc đáo cho đầu ra được in.

Tôi có một danh sách được sử dụng cho hai tiêu đề và một ma trận nên là nội dung của bảng. Thích như vậy:

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

Lưu ý rằng tên tiêu đề không nhất thiết phải có cùng độ dài. Các mục dữ liệu là tất cả các số nguyên, mặc dù.

Bây giờ, tôi muốn thể hiện điều này trong một định dạng bảng, đại loại như thế này:

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

Tôi có linh cảm rằng phải có cấu trúc dữ liệu cho việc này, nhưng tôi không thể tìm thấy nó. Tôi đã thử sử dụng từ điển và định dạng in, tôi đã thử các vòng lặp với thụt lề và tôi đã thử in dưới dạng chuỗi.

Tôi chắc chắn phải có một cách rất đơn giản để làm điều này, nhưng tôi có lẽ đang thiếu nó do thiếu kinh nghiệm.


1
+1, tôi chỉ cố gắng làm điều tương tự tối qua. Bạn chỉ đang cố in ra dòng lệnh hay bạn đang sử dụng mô-đun GUI?
HellaMad

Chỉ cần in vào dòng lệnh. Tuy nhiên, nó cần phải vượt qua một trường hợp kiểm thử đơn vị, vì vậy định dạng là khá quan trọng ở đây.
hjweide


1
Bản sao có thể có của Python: bảng ascii in đẹp?
Martin Thoma

Lưu ý rằng yêu cầu ở đây là khá chuyên biệt, vì các nhãn hàng và cột giống nhau. Vì vậy, đối với trường hợp cụ thể này, mã ad-hoc là một ví dụ hay về việc điều này có thể dễ dàng như thế nào. Nhưng các giải pháp khác ở đây có thể tốt hơn để hiển thị bảng chung hơn.
nealmcb

Câu trả lời:


189

Một số mã đặc biệt cho 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))

Điều này phụ thuộc vào str.format()Đặc tả định dạng Mini-Language .


3
Nếu sử dụng python2.6, hãy nhớ thêm chỉ mục team_list vào row_format: row_format = "{0:> 15} {1:> 15} {2:> 15}"
Luis Muñoz

1
Nếu dữ liệu trong phần thân lớn hơn các tiêu đề, bạn có thể đặt độ rộng cột dựa trên hàng dữ liệu đầu tiên. cho t trong dữ liệu [0]: row_format + = "{: <" + str (len (t) +5) + "}"
morgantaschuk 23/2/2016

587

Có một số gói python nhẹ và hữu ích cho mục đích này:

1. lập bảng : https://pypi.python.org/pypi/tabulation

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

lập bảng có nhiều tùy chọn để chỉ định tiêu đề và định dạng bảng.

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 có các tùy chọn để đọc dữ liệu từ cơ sở dữ liệu csv, html, sql. Ngoài ra, bạn có thể chọn tập hợp con của dữ liệu, sắp xếp bảng và thay đổi kiểu bảng.

3. texttable : 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  |
+-------+-----+

với texttable, bạn có thể điều khiển căn chỉnh ngang / dọc, kiểu viền và kiểu dữ liệu.

4. thuật ngữ : 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  |
+-------+-----+

với texttable, bạn có thể điều khiển căn chỉnh ngang / dọc, kiểu viền và kiểu dữ liệu.

Sự lựa chọn khác:

  • terminaltables Dễ dàng vẽ các bảng trong các ứng dụng terminal / console từ danh sách các chuỗi. Hỗ trợ các hàng nhiều dòng.
  • asciitable Asciitable có thể đọc và viết một loạt các định dạng bảng ASCII thông qua các Lớp đọc mở rộng tích hợp.

13
Tôi đã tìm thấy bảng là một công cụ rất hữu ích để xây dựng các công cụ CLI tập trung vào dữ liệu. Điều đó, kết hợp với nhấp chuột (nhấp vào cài đặt pip) và bạn đã có một món hầm thực sự.
alexbw

4
Điều này thật tuyệt vời, cảm ơn bạn. Cá nhân, bạn thích cái nào trong số ba?
Jim Raynor

Rực rỡ trả lời! PrettyTable rất tốt - sự cân bằng hoàn hảo giữa hai tùy chọn còn lại.
edesz

2
terminaltables tốt cho tiếng Trung Quốc, có thể là các ngôn ngữ không phải tiếng Anh khác
thinker3

5
Tôi chỉ chơi với các gói chính và IMO "beautifultable" - tốt nhất, được duy trì, API & doco tốt, hỗ trợ cho màu. "texttable" - API tốt, được duy trì, tốt nhưng sử dụng màu được sử dụng sẽ ném các bảng ra khỏi căn chỉnh. "Terminaltables" - tốt, chỉ thông qua các ví dụ mã. "PrettyTable" - ok, nhưng cũ, bảng 'tiêu đề' không hoạt động đối với tôi. "Tabulation" - tốt, nhưng coaligntừ khóa căn chỉnh cột không được hỗ trợ trong bản phát hành pypi chính thức. "bảng biểu" - trung bình, API phức tạp, không đủ các ví dụ sử dụng phổ biến.
abulka

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        

6
Điều này có vẻ rất hứa hẹn, cảm ơn, nhưng tôi đang cố gắng làm điều này mà không sử dụng bất kỳ thư viện nhập khẩu nào hơn là hoàn toàn cần thiết.
hjweide

26
Sử dụng gấu trúc chỉ để định dạng đầu ra có vẻ như Overkill (vốn O dự định).
Niels Bom

66
@NielsBom: đến định dạng đầu ra, ở lại để phân tích dữ liệu và mô hình hóa :)
jfs

30
@JFSebastian với tôi giống như "đến định dạng đầu ra, chạy đi la hét vì quá trình biên dịch numpy 10 phút khiến máy tính của tôi nghe như máy sấy tóc" ;-)
Niels Bom

4
@NielsBom: hiện pip install numpysử dụng bánh xe nhị phân trên hầu hết các nền tảng (không biên dịch) . Rõ ràng, các tùy chọn cài đặt nhị phân khác đã có sẵn ngay cả trước đó.
jfs

68

Python thực sự làm điều này khá dễ dàng.

Cái gì đó như

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

sẽ có đầu ra

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

% Trong chuỗi về cơ bản là một ký tự thoát và các ký tự theo sau nó cho python biết loại dữ liệu nào nên có. % Bên ngoài và sau chuỗi đang nói với python rằng bạn có ý định sử dụng chuỗi trước đó làm chuỗi định dạng và dữ liệu sau sẽ được đưa vào định dạng được chỉ định.

Trong trường hợp này, tôi đã sử dụng "% -12i" hai lần. Để chia nhỏ từng phần:

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

Từ các tài liệu: https://docs.python.org/2/l Library / stdtypes.html # String-formatted


Câu trả lời này đưa tôi đi đúng hướng để tìm thấy những gì tôi đang tìm kiếm! Đối với python 3, cuối cùng tôi đã sử dụng nó như print('%-20.2f' % position['deg'], '%-17.2f' % position['v2'])nơi .2chỉ định độ chính xác của phaof
Ross

25

Cập nhật câu trả lời của Sven Marnach để hoạt động trong 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))

9

Khi tôi làm điều này, tôi muốn có một số kiểm soát đối với các chi tiết về cách định dạng bảng. Cụ thể, tôi muốn các ô tiêu đề có định dạng khác với các ô cơ thể và chiều rộng của cột bảng chỉ rộng bằng mỗi ô cần có. Đây là giải pháp của tôi:

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

Đây là đầu ra:

                   | 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

8

Tôi nghĩ rằng đây là những gì bạn đang tìm kiếm.

Đó là một mô-đun đơn giản chỉ tính chiều rộng tối đa cần thiết cho các mục trong bảng và sau đó chỉ sử dụng bất côngsai trái để thực hiện một bản in đẹp của dữ liệu.

Nếu bạn muốn tiêu đề bên trái của bạn được căn phải, chỉ cần thay đổi cuộc gọi này:

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

Từ dòng 53 với:

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

8

Tôi biết rằng tôi đến bữa tiệc muộn, nhưng tôi chỉ làm một thư viện cho việc này mà tôi nghĩ có thể thực sự có ích. Nó cực kỳ đơn giản, đó là lý do tại sao tôi nghĩ bạn nên sử dụng nó. Nó được gọi là TableIT .

Sử dụng cơ bản

Để sử dụng nó, trước tiên hãy làm theo các hướng dẫn tải xuống trên Trang GitHub .

Sau đó nhập nó:

import TableIt

Sau đó lập danh sách các danh sách trong đó mỗi danh sách bên trong là một hàng:

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

Sau đó, tất cả những gì bạn phải làm là in nó:

TableIt.printTable(table)

Đây là đầu ra bạn nhận được:

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

Tên trường

Bạn có thể sử dụng tên trường nếu bạn muốn ( nếu bạn không sử dụng tên trường mà bạn không phải nói useFieldNames = false vì nó được đặt thành mặc định theo mặc định ):


TableIt.printTable(table, useFieldNames=True)

Từ đó bạn sẽ nhận được:

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

Có những cách sử dụng khác, ví dụ bạn có thể làm điều này:

import TableIt

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

TableIt.print(myList, useFieldNames=True)

Từ đó:

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

Hoặc bạn có thể làm:

import TableIt

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

TableIt.printTable(myList, useFieldNames=True)

Và từ đó bạn nhận được:

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

Màu sắc

Bạn cũng có thể sử dụng màu sắc.

Bạn sử dụng màu sắc bằng cách sử dụng tùy chọn màu ( theo mặc định, nó được đặt thành Không ) và chỉ định giá trị RGB.

Sử dụng ví dụ từ trên:

import TableIt

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

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

Sau đó, bạn sẽ nhận được:

nhập mô tả hình ảnh ở đây

Xin lưu ý rằng in màu có thể không phù hợp với bạn nhưng nó hoạt động chính xác như các thư viện khác in văn bản màu. Tôi đã thử nghiệm và mỗi màu duy nhất hoạt động. Màu xanh không bị rối như khi sử dụng mặc định34m chuỗi thoát ANSI (nếu bạn không biết đó là vấn đề gì). Dù sao, tất cả đều xuất phát từ thực tế là mọi màu sắc đều là giá trị RGB chứ không phải mặc định của hệ thống.

Thêm thông tin

Để biết thêm thông tin, hãy kiểm tra Trang GitHub


TableIt thực sự là một công cụ tốt. Đơn giản nhưng mạnh mẽ. Nhược điểm duy nhất tôi nghĩ là TableIt chưa tuyên bố GIẤY PHÉP
Endle_Zhenbo

@Endle_Zhenbo Này! Cảm ơn rất nhiều, tôi sẽ làm việc đó càng sớm càng tốt!
BeastCoder

@Endle_Zhenbo, tôi biết đã được một thời gian, nhưng cuối cùng tôi đã đặt giấy phép cho dự án.
BeastCoder

7

Python thuần 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)

Sẽ in

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

Một cách đơn giản để làm điều này là lặp qua tất cả các cột, đo chiều rộng của chúng, tạo một row_template cho chiều rộng tối đa đó, sau đó in các hàng. Đó không phải là chính xác những gì bạn đang tìm kiếm , bởi vì trong trường hợp này, trước tiên bạn phải đặt tiêu đề của bạn vào trong bàn, nhưng tôi nghĩ nó có thể hữu ích cho người khác.

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

Bạn sử dụng nó như thế này:

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

Hàm sau sẽ tạo bảng được yêu cầu (có hoặc không có numpy) với Python 3 (cũng có thể là Python 2). Tôi đã chọn đặt chiều rộng của mỗi cột để khớp với tên của nhóm dài nhất. Bạn có thể sửa đổi nó nếu bạn muốn sử dụng độ dài của tên nhóm cho mỗi cột, nhưng sẽ phức tạp hơn.

Lưu ý: Đối với tương đương trực tiếp trong Python 2, bạn có thể thay thế zipbằng iziptừ 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)

Điều này sẽ tạo ra bảng sau:

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

Nếu bạn muốn có dải phân cách dọc, bạn có thể thay thế " ".joinbằng " | ".join.

Người giới thiệu:


2

Tôi sẽ cố gắng lặp qua danh sách và sử dụng một trình định dạng CSV để thể hiện dữ liệu bạn muốn.

Bạn có thể chỉ định các tab, dấu phẩy hoặc bất kỳ char nào khác làm dấu phân cách.

Mặt khác, chỉ cần lặp qua danh sách và in "\ t" sau mỗi phần tử

http://docs.python.org/l Library / csv.html


Đây là nỗ lực ban đầu của tôi, nó có thể được thực hiện, nhưng có vẻ như rất nhiều nỗ lực để có được định dạng hoàn hảo.
hjweide

2

Tôi thấy điều này chỉ tìm cách để xuất các cột đơn giản. Nếu bạn chỉ cần các cột không cầu kỳ , thì bạn có thể sử dụng:

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

EDIT: Tôi đã cố gắng đơn giản nhất có thể, và do đó đã làm một số điều thủ công thay vì sử dụng danh sách các đội. Để khái quát cho câu hỏi thực tế của OP:

#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()

Ouputs:

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

Nhưng điều này dường như không còn đơn giản hơn các câu trả lời khác, có lẽ lợi ích mà nó không yêu cầu nhập khẩu nữa. Nhưng câu trả lời của @ campkeith đã đáp ứng điều đó và mạnh mẽ hơn vì nó có thể xử lý nhiều độ dài nhãn khác nhau.


1
điều này được thảo luận trên meta meta.stackoverflow.com/questions/381571/ từ
Félix Gagnon-Grenier
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.