Printing aligned nested dictionary with keys as rows

Question:

Preface: I do not have pandas, or itertools and have very limited modules in this environment so I need to keep this as pythonic as possible. Im using 3.7.3 on Buster debian.

I have a nested dictionary called all_dicts that has:

  • All keys will appear in the same order with the same name across all dictionaries (e.g. all dictionaries will have "Authors" and it will be first)
  • Every dictionary will have a key/value pairing (e.g. if there is no ISBN yet it will have a ‘0’ value)
  • All keys/values are strings
  • All values are expected vary in length (maybe not year, not for a while at least)

The dict of dicts:

all_dicts = {
     'dict_0': {'Author(s)': 'Ian Flemming', 'Year': '1956', 'Title': 'Diamonds are Forever', 'surname': 'Flemming', 'ISBN Number will go here': '9781612185460'},
     'dict_1': {'Author(s)': 'Jules Verne', 'Year': '1870', 'Title': '20,000 Leagues Under the Sea', 'surname': 'Verne', 'ISBN Number will go here': '0451531698'}}

The Goal:
What I am attempting to print (the #### doesnt have to be present)

#######                     dict_0                 dict_1
Authors                     Ian Flemming           Jules Verne
Year                        1956                   1870
Title                       Diamonds are Forever   20,000 Leagues Under the Sea
Surname                     Flemming               Verne
ISBN Number will go here    9781612185460          0451531698

What I have gathered and pieced together (mostly from other SO pots) so far
Gathering the "rows"

row_label = (max(all_dicts.values(), key=len))
for i in row_label:
  print(i)

Results in:

Author(s)
Year
Title
surname
ISBN Number will go here

Attempting to loop through to get "columns"

for j in all_dicts:
  print(j + "n" + "n".join(map(str, [all_dicts[j][q] for q in all_dicts[j]])))
  print("======") 

Results in

dict_0
Ian Flemming
1956
Diamonds are Forever
Flemming
9781612185460
======
dict_1
Jules Verne
1870
20,000 Leagues Under the Sea
Verne
0451531698
======

So far I’ve got each component (rows and columns) individually and here is where I am struggling to figure out how to piece these together.

def get_keys(my_dict):
    keys = list(my_dict.keys())
    keys = my_dict[keys[0]].keys()
    keys = list(keys)
    return keys
print("ttt" + "tt".join(all_dicts))
for key in get_keys(all_dicts):
    print(key + " " + "t".join(str(all_dicts[j].get(key)) for j in all_dicts), end="n")

Results in the desired style, just with horrible formatting/spacing.

            dict_0      dict_1
Author(s) Ian Flemming  Jules Verne
Year 1956   1870
Title Diamonds are Forever  20,000 Leagues Under the Sea
surname Flemming    Verne
ISBN Number will go here 9781612185460  0451531698

Another attempt.

print("ttt" + "tt".join(all_dicts))
row_label = (max(all_dicts.values(), key=len))
for i in row_label:
  print(i + "tt" + "t".join(str(all_dicts[j].get(i)) for j in all_dicts))

Results in

            dict_0      dict_1
Author(s)       Ian Flemming    Jules Verne
Year        1956    1870
Title       Diamonds are Forever    20,000 Leagues Under the Sea
surname     Flemming    Verne
ISBN Number will go here        9781612185460   0451531698

How can I go about tabularizing this given nested dictionaries?

Asked By: DevNull

||

Answers:

Your issue at the end is to print strings of different sizes into a same size output

You can’t only use t or a space, to separate the things, you need string formatting

def format_row(row_header: str, values):
    return "".join(f"{item:30s}" for item in [row_header, *values])


print(format_row('', all_dicts))

for key in all_dicts['dict_0']:
    values = [value[key] for value in all_dicts.values()]
    print(format_row(key, values))
Answered By: azro

Here is one way without any additional library.
I combined the dicts and printed them (without joining each row to a string) by string formatting with a fixed width.
Have a look here how to format strings.

all_dicts = {
     'dict_0': {'Author(s)': 'Ian Flemming', 'Year': '1956', 'Title': 'Diamonds are Forever', 'surname': 'Flemming', 'ISBN Number will go here': '9781612185460'},
     'dict_1': {'Author(s)': 'Jules Verne', 'Year': '1870', 'Title': '20,000 Leagues Under the Sea', 'surname': 'Verne', 'ISBN Number will go here': '0451531698'}}
d = {}
for key in all_dicts:
    for k,v in all_dicts[key].items():
        if k not in d:
            d[k] = [v]
        else:
            d[k].append(v)
print(d)


print("{0:<50} {1:<50} {2:<50}".format("###", "dict1", "dict2")) # formatting with "str.format()"
for k, v in d.items():
    print(f"{k:<50} {v[0]:<50} {v[1]:<50}") # formatting with f-strings

Output:

# d
{'Author(s)': ['Ian Flemming', 'Jules Verne'], 
'Year': ['1956', '1870'], 
'Title': ['Diamonds are Forever', '20,000 Leagues Under the Sea'], 
'surname': ['Flemming', 'Verne'], 
'ISBN Number will go here': ['9781612185460', '0451531698']}

# print statement

###                                      dict1                                    dict2                                   
Author(s)                                Ian Flemming                             Jules Verne                             
Year                                     1956                                     1870                                    
Title                                    Diamonds are Forever                     20,000 Leagues Under the Sea            
surname                                  Flemming                                 Verne                                   
ISBN Number will go here                 9781612185460                            0451531698  
Answered By: Rabinzel
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.