Python – Printing a dictionary as a horizontal table with headers

Question:

I have a dictionary:

import math
import random

d = {1: ["Spices", math.floor(random.gauss(40, 5))],
    2: ["Other stuff", math.floor(random.gauss(20, 5))],
    3: ["Tea", math.floor(random.gauss(50, 5))],
    10: ["Contraband", math.floor(random.gauss(1000, 5))],
    5: ["Fruit", math.floor(random.gauss(10, 5))],
    6: ["Textiles", math.floor(random.gauss(40, 5))]
}

I want to print it out so it lines up nicely with headers. Can I add the headers to the dictionary and always be sure they come out on top?
I’ve seen a few ways to do it vertically but I’d like to have it come out with max column widths close to the max str() or int().

Example:

Key___________________Label______________________Number
1______________________Spices_____________________42
2______________________Other Stuff_____________16
etc

Apparently I can’t even do this inside of this editor manually, but I hope the idea comes across.
I also don’t really want the __ either. Just a place holder.
Thanks all.

Asked By: Faller

||

Answers:

You can use string formatting in python2:

    print "{:<8} {:<15} {:<10}".format('Key','Label','Number')
    for k, v in d.iteritems():
        label, num = v
        print "{:<8} {:<15} {:<10}".format(k, label, num)

Or, string formatting in python3:

    print("{:<8} {:<15} {:<10}".format('Key','Label','Number'))
    for k, v in d.items():
        label, num = v
        print("{:<8} {:<15} {:<10}".format(k, label, num))

Output:

Key      Label           Number    
1        Spices          38.0      
2        Other stuff     24.0      
3        Tea             44.0      
5        Fruit           5.0       
6        Textiles        37.0      
10       Contraband      1000.0 
Answered By: Ashwini Chaudhary

You can use ljust or rjust string methods:

print key.ljust(10), label.ljust(30), number.ljust(20)
Answered By: user1941407

I was looking for a solution with unknown columns width to print a database table. So here it is:

def printTable(myDict, colList=None):
   """ Pretty print a list of dictionaries (myDict) as a dynamically sized table.
   If column names (colList) aren't specified, they will show in random order.
   Author: Thierry Husson - Use it as you want but don't blame me.
   """
   if not colList: colList = list(myDict[0].keys() if myDict else [])
   myList = [colList] # 1st row = header
   for item in myDict: myList.append([str(item[col] if item[col] is not None else '') for col in colList])
   colSize = [max(map(len,col)) for col in zip(*myList)]
   formatStr = ' | '.join(["{{:<{}}}".format(i) for i in colSize])
   myList.insert(1, ['-' * i for i in colSize]) # Seperating line
   for item in myList: print(formatStr.format(*item))

Sample:

printTable([{'a':123,'bigtitle':456,'c':789},{'a':'x','bigtitle':'y','c':'z'}, 
    {'a':'2016-11-02','bigtitle':1.2,'c':78912313213123}], ['a','bigtitle','c'])

Output:

a          | bigtitle | c             
---------- | -------- | --------------
123        | 456      | 789           
x          | y        | z             
2016-11-02 | 1.2      | 78912313213123

In Psycopg context, you can use it this way:

curPG.execute("SELECT field1, field2, ... fieldx FROM mytable")
printTable(curPG.fetchall(), [c.name for c in curPG.description])

If you need a variant for multi-lines rows, here it is:

def printTable(myDict, colList=None, sep='uFFFA'):
   """ Pretty print a list of dictionaries (myDict) as a dynamically sized table.
   If column names (colList) aren't specified, they will show in random order.
   sep: row separator. Ex: sep='n' on Linux. Default: dummy to not split line.
   Author: Thierry Husson - Use it as you want but don't blame me.
   """
   if not colList: colList = list(myDict[0].keys() if myDict else [])
   myList = [colList] # 1st row = header
   for item in myDict: myList.append([str(item[col] or '') for col in colList])
   colSize = [max(map(len,(sep.join(col)).split(sep))) for col in zip(*myList)]
   formatStr = ' | '.join(["{{:<{}}}".format(i) for i in colSize])
   line = formatStr.replace(' | ','-+-').format(*['-' * i for i in colSize])
   item=myList.pop(0); lineDone=False
   while myList or any(item):
      if all(not i for i in item):
         item=myList.pop(0)
         if line and (sep!='uFFFA' or not lineDone): print(line); lineDone=True
      row = [i.split(sep,1) for i in item]
      print(formatStr.format(*[i[0] for i in row]))
      item = [i[1] if len(i)>1 else '' for i in row]

Sample:

sampleDict = [{'multi lines title': 12, 'bigtitle': 456, 'third column': '7 8 9'},
{'multi lines title': 'w x y z', 'bigtitle': 'b1 b2', 'third column': 'z y x'},
{'multi lines title': '2', 'bigtitle': 1.2, 'third column': 78912313213123}]

printTable(sampleDict, sep=' ')

Output:

bigtitle | multi | third         
         | lines | column        
         | title |               
---------+-------+---------------
456      | 12    | 7             
         |       | 8             
         |       | 9             
---------+-------+---------------
b1       | w     | z             
b2       | x     | y             
         | y     | x             
         | z     |               
---------+-------+---------------
1.2      | 2     | 78912313213123

Without sep parameter, printTable(sampleDict) gives you:

bigtitle | multi lines title | third column  
---------+-------------------+---------------
456      | 12                | 7 8 9         
b1 b2    | w x y z           | z y x         
1.2      | 2                 | 78912313213123
Answered By: Le Droid

Based on Le Droid’s code, I added separator ‘-‘ for each row which could make the print more clear. Thanks, Le Droid.

def printTable(myDict, colList=None):
    if not colList: 
        colList = list(myDict[0].keys() if myDict else [])
    myList = [colList] # 1st row = header
    for item in myDict: 
        myList.append([str(item[col] or '') for col in colList])
    #maximun size of the col for each element
    colSize = [max(map(len,col)) for col in zip(*myList)]
    #insert seperating line before every line, and extra one for ending. 
    for i in  range(0, len(myList)+1)[::-1]:
         myList.insert(i, ['-' * i for i in colSize])
    #two format for each content line and each seperating line
    formatStr = ' | '.join(["{{:<{}}}".format(i) for i in colSize])
    formatSep = '-+-'.join(["{{:<{}}}".format(i) for i in colSize])
    for item in myList: 
        if item[0][0] == '-':
            print(formatSep.format(*item))
        else:
            print(formatStr.format(*item))

Output:

-----------+----------+---------------
a          | bigtitle | c             
-----------+----------+---------------
123        | 456      | 789           
-----------+----------+---------------
x          | y        | z             
-----------+----------+---------------
2016-11-02 | 1.2      | 78912313213123
-----------+----------+---------------
Answered By: Luke

I would prefer pandas DataFrame

import pandas as pd
data = {'Name': ['a', 'b', 'c'], 'Age': [10, 11, 12]}
df = pd.DataFrame(data)
print(df)

Output:

  Name  Age
0    a   10
1    b   11
2    c   12

check out more about printing pretty a dataframe here

Answered By: vivek_reddy

String formatting provides a nice, simple solution. This answer is an update for Python 3 of the nice answer from @Ashwini.

str_fmt = "{:<8} {:<15} {:<10}"
print(str_fmt.format('Key','Label','Number'))
for k, v in d.items():
    label, num = v
    print(str_fmt.format(k, label, num))
Answered By: SpinUp

I would always use pandas to print the table-type structure neatly.

It is straightforward to create a pandas dataframe from your data structure.

df = pd.DataFrame(
    [[key] + list(value) for key, value in d.items()], 
    columns=['Key', 'Label', 'Number']
)

columns is used to define the names you would want to give to the individual columns of data.

Then, you can print it (ignoring the pandas dataframe index) as:

print(df.to_string(index=False))

Your output will print as:

 Key       Label  Number
   1      Spices      40
   2 Other stuff      14
   3         Tea      52
  10  Contraband     992
Answered By: Suraj Regmi
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.