How to print a list of dicts as an aligned table?

2024/10/12 0:27:59

So after going through multiple questions regarding the alignment using format specifiers I still can't figure out why the numerical data gets printed to stdout in a wavy fashion.

def create_data(soup_object,max_entry=None):max_=max_entryentry=dict()for a in range(1,int(max_)+1):entry[a]={'Key':a,'Title':soup_object[a].div.text.strip(),'Link':soup_object[a].div.a['href'],'Seeds':soup_object[a](attrs={'align':'right'})[0].text.strip(),'Leechers':soup_object[a](attrs={'align':'right'})[1].text.strip()}yield entry[a]tpb_get_data=tuple(create_data(soup_object=tpb_soup.body.table.find_all("tr"),max_entry=5))
for data in tpb_get_data:print('{0} {1:<11}  {2:<25} {3:<25} '.format(data['Key'], data['Title'], data['Seeds'],data['Leechers']))

I tried using f-strings with the formatting specifiers but still it prints the data in the following way, can someone please help me figure this out.

 1 Salvation.S02E11.HDTV.x264-KILLERS  262         19 2 Salvation.S02E13.WEB.x264-TBS[ettv]  229         25 3 Salvation.S02E08.HDTV.x264-KILLERS  178         21 4 Salvation.S02E01.HDTV.x264-KILLERS  144          11 5 Salvation.S02E09.HDTV.x264-SVA[ettv]  129       14

I have read most of the questions regarding this, I would like to know if there is a raw method rather than using a library like tabulate which does an excellent job. But I also want to learn how to do this without any library.

Answer

You get a misaligned result because you did not count the length of the titles correct. You only reserved 11 characters, where the first is already 34 characters long.

Easiest is to have your program count for you:

key_len,title_len,seed_len,leech_len = ( max(len(item[itemname]) for item in tpb_get_data) for itemname in ['Key','Title','Seeds','Leechers'] )fmtstring = '{{:{:d}}} {{:{:d}}} {{:{:d}}} {{:{:d}}}'.format(key_len,title_len,seed_len,leech_len)for data in tpb_get_data:print(fmtstring.format(data['Key'], data['Title'], data['Seeds'],data['Leechers']))

with the much better result

1 Salvation.S02E11.HDTV.x264-KILLERS   262 19
2 Salvation.S02E13.WEB.x264-TBS[ettv]  229 25
3 Salvation.S02E08.HDTV.x264-KILLERS   178 21
4 Salvation.S02E01.HDTV.x264-KILLERS   144 11
5 Salvation.S02E09.HDTV.x264-SVA[ettv] 129 14

(Additional only)

Here is a more generalized approach that uses a list of to-print key names and is able to generate all other required variables on the fly. It does not need hardcoding the names of the variables nor fixating their order – the order is taken from that list. Adjustments of the items to show all go in one place: that same list, get_items. The output separator can be changed in the fmtstring line, for example using a tab or more spaces between the items.

get_items = ['Key','Title','Leechers','Seeds']
lengths = ( max(len(item[itemname]) for item in tpb_get_data) for itemname in get_items )
fmtstring = ' '.join(['{{:{:d}}}' for i in range(len(get_items))]).format(*lengths)for data in tpb_get_data:print(fmtstring.format(*[data[key] for key in get_items]))

It works as follows:

  1. The lengths list is filled with the maximum length of each named key taken from the get_items list.
  2. This returns a list; the fmtstring repeats the format instruction {:d} for each of these items and fills in the number. The outer {{: and }} gets translated by format into {: and } so the end result will be {:number} for each length. These separate format strings are joined into a single longer format string.
  3. Finally, the loop over the actual data prints the items from get_items. The list comprehension looks them up; the * notation forces the list to be 'written out' as separate values, instead of returning the entire list as one.

Thanks to @Georgy for suggesting to look for a less hardcoded variety.

https://en.xdnf.cn/q/118257.html

Related Q&A

abstract classes in python: Enforcing type

My question is related to this question Is enforcing an abstract method implementation unpythonic? . I am using abstract classes in python but I realize that there is nothing that stops the user from …

Convert image array to original svs format

Im trying to apply a foreground extraction to a SVS image (Whole Slide Image) usign OpenSlide library.First, I converted my image to an array to work on my foreground extraction:image = np.asarray(oslI…

Printing bytestring via variable

I have the following Unicode text stored in variable:myvariable = Gen\xe8veWhat I want to do is to print myvariable and show this:GenveI tried this but failed:print myvariable.decode(utf-8)Whats the ri…

Loop and arrays of strings in python

I have the following data set:column1HL111 PG3939HL11 HL339PG RC--HL--PGI am attempting to write a function that does the following:Loop through each row of column1 Pull only the alphabet and put into…

2 Dendrograms + Heatmap from condensed correlationmatrix with scipy

I try to create something like this: plotting results of hierarchical clustering ontop of a matrix of data in pythonUnfortunatelly when I try to execute the code, I get the following warnings:Warning (…

Iterator example from Dive Into Python 3

Im learning Python as my 1st language from http://www.diveintopython3.net/. On Chp 7, http://www.diveintopython3.net/iterators.html, there is an example of how to use an iterator.import redef build_mat…

Getting a 500 Internal Server Error using render_template and Flask [duplicate]

This question already has answers here:How to debug a Flask app(13 answers)Comments not working in jinja2(2 answers)Closed 5 years ago.I am trying to use Flask to render an HTML template. I had it work…

Bokeh use of Column Data Source and Box_Select

Im lost as to how to set up a Column Data Source so that I can select points from one graph and have the corresponding points highlighted in another graph. I am trying to learn more about how this work…

How Does a Pyqtgraph Export for Three Subplots Look Like?

Using PyQtGraph, I would like to generate three sub plots in one chart and export this chart to a file.As I will repeat this a lot of times, it is quite performance sensitive. Therefore I do not need t…

Use class variables as instance vars?

What I would like to do there is declaring class variables, but actually use them as vars of the instance. I have a class Field and a class Thing, like this:class Field(object):def __set__(self, instan…