การพิมพ์รายการเป็นข้อมูลแบบตาราง


366

ฉันค่อนข้างใหม่กับ 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

ฉันมีลางสังหรณ์ว่าต้องมีโครงสร้างข้อมูลสำหรับสิ่งนี้ แต่ฉันไม่พบมัน ฉันได้ลองใช้พจนานุกรมและจัดรูปแบบการพิมพ์ฉันได้ลองวนซ้ำกับการเยื้องและฉันได้ลองพิมพ์เป็นสตริง

ฉันแน่ใจว่าจะต้องมีวิธีที่ง่ายมากในการทำเช่นนี้ แต่ฉันอาจจะพลาดเพราะขาดประสบการณ์


1
+1 ฉันเพิ่งพยายามทำสิ่งเดียวกันเมื่อคืนนี้ คุณแค่พยายามพิมพ์ไปยังบรรทัดคำสั่งหรือคุณใช้โมดูล GUI หรือไม่?
HellaMad

เพียงพิมพ์ไปที่บรรทัดคำสั่ง อย่างไรก็ตามต้องผ่านกรณีทดสอบหน่วยดังนั้นการจัดรูปแบบจึงค่อนข้างสำคัญ
hjweide



โปรดทราบว่าความต้องการที่นี่ค่อนข้างพิเศษเนื่องจากป้ายชื่อแถวและคอลัมน์เหมือนกัน ดังนั้นในกรณีนี้รหัส ad-hoc เป็นตัวอย่างที่ดีของความง่ายในการใช้งาน แต่โซลูชันอื่น ๆ ที่นี่อาจดีกว่าสำหรับการแสดงตารางทั่วไปเพิ่มเติม
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()และรูปแบบข้อมูลจำเพาะ Mini-ภาษา


3
หากใช้ python2.6 อย่าลืมเพิ่มดัชนี team_list ใน row_format: row_format = "{0:> 15} {1:> 15} {2:> 15}"
Luis Muñoz

1
หากข้อมูลในร่างกายมีขนาดใหญ่กว่าส่วนหัวคุณสามารถตั้งค่าความกว้างคอลัมน์ตามแถวข้อมูลแรก สำหรับ t in data [0]: row_format + = "{: <" + str (len (t) +5) + "}"
morgantaschuk

587

มีบางแพคเกจหลามที่มีประโยชน์และมีประโยชน์สำหรับวัตถุประสงค์นี้:

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

ตารางมีตัวเลือกมากมายในการระบุส่วนหัวและรูปแบบตาราง

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

ด้วย 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 คุณสามารถควบคุมการจัดเรียงแนวนอน / แนวตั้งสไตล์ชายแดนและชนิดข้อมูล

ตัวเลือกอื่น:

  • เทอร์มินัลตารางวาดตารางในแอปพลิเคชันเทอร์มินัล / คอนโซลได้อย่างง่ายดายจากรายการของสตริง รองรับแถวหลายบรรทัด
  • asciitable Asciitable สามารถอ่านและเขียนรูปแบบตาราง ASCII ที่หลากหลายผ่านทางตัวอ่านส่วนขยายภายใน

13
ฉันพบว่าตารางเป็นเครื่องมือที่มีประโยชน์มากสำหรับการสร้างเครื่องมือ CLI ที่เน้นข้อมูล เมื่อรวมกับคลิก (คลิกติดตั้ง pip) แล้วคุณจะได้สตูว์จริง
alexbw

4
ขอบคุณมาก โดยส่วนตัวแล้วคุณจะเลือกอันไหนในหมู่สามคนนี้?
Jim Raynor

คำตอบที่ยอดเยี่ยม! PrettyTable ดีมาก - ความสมดุลที่สมบูรณ์แบบระหว่างอีกสองตัวเลือก
edesz

2
เทอร์มินัลสำหรับภาษาจีนอาจเป็นภาษาอื่นที่ไม่ใช่ภาษาอังกฤษ
thinker3

5
ฉันเพิ่งเล่นกับแพ็คเกจหลักและ IMO "beautifultable" - ดีที่สุดได้รับการบำรุงรักษาดี API & doco สนับสนุนสี "texttable" - ดี, การบำรุงรักษา, API ที่ดี แต่การใช้งานแบบใช้สีจะทำให้ตารางไม่อยู่ในแนวเดียวกัน "เทอร์มินัล" - ดี doco ผ่านตัวอย่างรหัสเท่านั้น "PrettyTable" - โอเค แต่เก่า 'ชื่อ' ของตารางไม่เหมาะกับฉัน "Tabulate" - ดี แต่coalignคำหลักการจัดเรียงคอลัมน์ไม่ได้รับการสนับสนุนในรุ่นไพพีพีอย่างเป็นทางการ "tableprint" - เฉลี่ย, ซับซ้อน API, ตัวอย่างการใช้งานทั่วไปไม่เพียงพอ
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
ดูเหมือนว่าจะเป็นสิ่งที่ดีมากขอบคุณ แต่ฉันพยายามทำสิ่งนี้โดยไม่ต้องใช้ห้องสมุดนำเข้ามากกว่าที่จำเป็นจริงๆ
hjweide

26
การใช้หมีแพนด้าสำหรับการจัดรูปแบบผลลัพธ์ดูเหมือน Overkill (ตั้งใจใช้ตัวพิมพ์ใหญ่ O)
Niels Bom

66
@NielsBom: มาสำหรับการส่งออกการจัดรูปแบบ, การเข้าพักสำหรับการวิเคราะห์ข้อมูลและการสร้างแบบจำลอง :)
jfs

30
@JFSebastian สำหรับฉันมันเป็นเหมือน "มาสำหรับการจัดรูปแบบผลลัพธ์วิ่งออกไปตะโกนเพราะการรวบรวม numpy 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

% ภายในสตริงนั้นเป็นตัวละครหลักในการหลบหนีและตัวอักษรที่ตามมาก็บอกว่าไพ ธ อนควรจัดรูปแบบข้อมูลแบบใด % ภายนอกและหลังจากสตริงบอก 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
Ross


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

8

ฉันคิดว่านี่คือสิ่งที่คุณกำลังมองหา

เป็นโมดูลง่าย ๆ ที่คำนวณความกว้างสูงสุดที่ต้องการสำหรับรายการตารางจากนั้นใช้rjustและljustเพื่อทำการพิมพ์ข้อมูล

หากคุณต้องการจัดชิดซ้ายของคุณเพียงแค่เปลี่ยนสายนี้:

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

จากบรรทัดที่ 53 ด้วย:

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

8

ฉันรู้ว่าฉันมางานปาร์ตี้ช้า แต่ฉันเพิ่งสร้างห้องสมุดเพื่อสิ่งนี้ซึ่งฉันคิดว่าจะช่วยได้จริงๆ มันง่ายมากนั่นเป็นเหตุผลที่ฉันคิดว่าคุณควรใช้มัน มันถูกเรียกว่า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ลำดับการหลบหนีของ ANSI ที่เป็นค่าเริ่มต้น(ถ้าคุณไม่รู้ว่ามันไม่สำคัญ) อย่างไรก็ตามทุกอย่างมาจากความจริงที่ว่าทุกสีเป็นค่า RGB แทนที่จะเป็นค่าเริ่มต้นของระบบ

ข้อมูลเพิ่มเติม

สำหรับข้อมูลเพิ่มเติมตรวจสอบหน้า GitHub


TableIt เป็นเครื่องมือที่ดีจริงๆ เรียบง่าย แต่ทรงพลัง ข้อเสียเดียวที่ฉันคิดว่า TableIt ไม่ได้ประกาศใบอนุญาต
Endle_Zhenbo

@Endle_Zhenbo เฮ้! ขอบคุณมากฉันจะทำงานให้เร็วที่สุด!
BeastCoder

@Endle_Zhenbo ฉันรู้ว่ามันใช้เวลานาน แต่ในที่สุดฉันก็วางใบอนุญาตในโครงการ
BeastCoder

7

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

ฟังก์ชั่นต่อไปนี้จะสร้างตารางที่ร้องขอ (มีหรือไม่มีตัวเลข) ด้วย 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ด้วย

อ้างอิง:


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)

แก้ไข: ฉันพยายามที่จะง่ายที่สุดเท่าที่จะทำได้และทำบางสิ่งด้วยตนเองแทนที่จะใช้รายชื่อทีม เพื่อสรุปคำถามที่แท้จริงของ 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()

เพื่อถ่ายทอด:

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

แต่นี่ดูเหมือนจะไม่ง่ายไปกว่าคำตอบอื่น ๆ อีกต่อไปซึ่งอาจเป็นประโยชน์ที่ไม่ต้องใช้การนำเข้าอีกต่อไป แต่คำตอบของ @ campkeith พบแล้วและมีความแข็งแกร่งกว่าเพราะสามารถรองรับความยาวของฉลากได้หลากหลายกว่า


1
สิ่งนี้ถูกกล่าวถึงใน meta meta.stackoverflow.com/questions/381571/…
Félix Gagnon-Grenier
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.