{"id":7429,"date":"2021-10-07T18:05:24","date_gmt":"2021-10-07T17:05:24","guid":{"rendered":"https:\/\/www.blopig.com\/blog\/?p=7429"},"modified":"2021-10-22T18:53:58","modified_gmt":"2021-10-22T17:53:58","slug":"list-comprehension-an-elegant-python-feature-inspired-by-mathematical-set-theory","status":"publish","type":"post","link":"https:\/\/www.blopig.com\/blog\/2021\/10\/list-comprehension-an-elegant-python-feature-inspired-by-mathematical-set-theory\/","title":{"rendered":"List comprehension: an elegant Python feature inspired by mathematical set theory"},"content":{"rendered":"\n<p>Even though I have now deeply entered into the fascinating world of statistical machine learning and computational chemistry, my original background is very much in pure mathematics. Having spent some of my intellectually formative years in this highly purified and abstract universe, I still love to think in terms of sets, ordered tuples and well-defined functions whenever I have the luxury of being able to do so. This might be why list comprehension is one of my favourite features in Python.<\/p>\n\n\n\n<p>List comprehension allows you to efficiently map a function over a list using elegant notation inspired by mathematical set theory. Let us first consider a (mathematical) set<\/p>\n\n\n\n<p><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/s0.wp.com\/latex.php?latex=A+%3A%3D+%5C%7B1%2C+3%2C+7+%5C%7D.&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002\" alt=\"A := &#92;{1, 3, 7 &#92;}.\" class=\"latex\" \/><\/p>\n\n\n\n<!--more-->\n\n\n\n<p>Then<\/p>\n\n\n\n<p><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/s0.wp.com\/latex.php?latex=B+%3A%3D+%5C%7B+a%5E2+%5C+%5Cvert+%5C+a+%5Cin+A++%5C%7D+%3D+%5C%7B1%2C+9%2C+49+%5C%7D+&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002\" alt=\"B := &#92;{ a^2 &#92; &#92;vert &#92; a &#92;in A  &#92;} = &#92;{1, 9, 49 &#92;} \" class=\"latex\" \/><\/p>\n\n\n\n<p>describes a new set which is obtained by mapping the function <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/s0.wp.com\/latex.php?latex=f%28x%29+%3D+x%5E2&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002\" alt=\"f(x) = x^2\" class=\"latex\" \/> over the set <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/s0.wp.com\/latex.php?latex=A&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002\" alt=\"A\" class=\"latex\" \/>. In Python, you can use the syntax of list comprehension to do something completely analogous with lists!<\/p>\n\n\n\n<p>To see this, lets look at the following Python list:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">A = [1, 3, 7].<\/pre>\n\n\n\n<p>Assume we want to map the square function <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/s0.wp.com\/latex.php?latex=f%28x%29+%3D+x%5E2&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002\" alt=\"f(x) = x^2\" class=\"latex\" \/> over this list. A slow and rather clumsy way to achieve this is by using a for-loop and the &#8220;append&#8221; command:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">B = []\n\nfor a in A:\n    B.append(a**2)\n\n# B = [1, 9, 49]<\/pre>\n\n\n\n<p> However, the exact same result can be generated using the following concise and elegant expression:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">B = [a**2 for a in A] # B = [1, 9, 49].<\/pre>\n\n\n\n<p>Such expressions are called list comprehensions in Python. The analogy to the set theory notation from above is obvious. <\/p>\n\n\n\n<p>But wait, there is more. What if we want to filter the original list <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/s0.wp.com\/latex.php?latex=A&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002\" alt=\"A\" class=\"latex\" \/> in some way before mapping a function over it? For example, what if we only want to consider elements of <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/s0.wp.com\/latex.php?latex=A&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002\" alt=\"A\" class=\"latex\" \/> which are larger than <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/s0.wp.com\/latex.php?latex=2&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002\" alt=\"2\" class=\"latex\" \/>? <\/p>\n\n\n\n<p>Instead of writing<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">B = []\n\nfor a in A:\n    if a &gt; 2:\n        B.append(a**2)\n\n# B = [9, 49]<\/pre>\n\n\n\n<p>we just write<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">B = [a**2 for a in A if a &gt; 2] # B = [9, 49].<\/pre>\n\n\n\n<p>You get the idea.<\/p>\n\n\n\n<p>Of course you can also use list comprehensions merely for filtering, technically by mapping the identity function over the original list:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">C = [a for a in A if a &gt; 2] # C = [3, 7].<\/pre>\n\n\n\n<p>Not only are list comprehensions much more compact and elegant than for-loops, they also often tend to be faster. Lets do a simple experiment on my laptop. Let<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">R = list(range(10**7))<\/pre>\n\n\n\n<p> be the list of the first <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/s0.wp.com\/latex.php?latex=10%5E7&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002\" alt=\"10^7\" class=\"latex\" \/> natural numbers starting at <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/s0.wp.com\/latex.php?latex=0&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002\" alt=\"0\" class=\"latex\" \/>. Evaluating<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">S = []\nfor r in R:\n    S.append(r**2)<\/pre>\n\n\n\n<p>takes <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/s0.wp.com\/latex.php?latex=%5Cmathbf%7B3.56%7D&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002\" alt=\"&#92;mathbf{3.56}\" class=\"latex\" \/> seconds while evaluating<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">S = [r**2 for r in R]<\/pre>\n\n\n\n<p>only takes <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/s0.wp.com\/latex.php?latex=%5Cmathbf%7B2.33%7D&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002\" alt=\"&#92;mathbf{2.33}\" class=\"latex\" \/> seconds. So in this case, we get a reduction in computational time of about <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/s0.wp.com\/latex.php?latex=%5Cmathbf%7B35+%5C%25%7D&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002\" alt=\"&#92;mathbf{35 &#92;%}\" class=\"latex\" \/>. Time estimates were obtained by averaging over <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/s0.wp.com\/latex.php?latex=10&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002\" alt=\"10\" class=\"latex\" \/> independent trials.<\/p>\n\n\n\n<p>Note that list comprehensions are certainly not restricted to lists of numbers, but can also easily be used with lists of strings, lists of lists, or lists of anything, really. There are also set- and dictionary comprehensions in Python which make it possible to directly create Python sets and Python dictionaries from Python lists in a set-theoretic manner. <\/p>\n\n\n\n<p>My appreciation of list comprehensions is shared by the well-known MIT researcher, AI enthusiast and podcaster Lex Fridman, who even dedicated a short YouTube video to this feature. I used his video as a source for this blog entry and encourage you to watch it here:<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Best feature of Python | List Comprehensions\" width=\"625\" height=\"352\" src=\"https:\/\/www.youtube.com\/embed\/belS2Ek4-ow?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<p>  In summary, having the concept of list comprehension at your fingertips when programming in Python will allow you to write code which is more compact, efficient and beautiful. Go play around with it!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Even though I have now deeply entered into the fascinating world of statistical machine learning and computational chemistry, my original background is very much in pure mathematics. Having spent some of my intellectually formative years in this highly purified and abstract universe, I still love to think in terms of sets, ordered tuples and well-defined [&hellip;]<\/p>\n","protected":false},"author":84,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"nf_dc_page":"","wikipediapreview_detectlinks":true,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"ngg_post_thumbnail":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[29,221],"tags":[152],"ppma_author":[556],"class_list":["post-7429","post","type-post","status-publish","format-standard","hentry","category-code","category-python","tag-python"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"authors":[{"term_id":556,"user_id":84,"is_guest":0,"slug":"markusd","display_name":"Markus Dablander","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/d0047b5862940cb3a1b68dfa3f0735d6602b1e619fb299881b56cbf60d9fd8e1?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/posts\/7429","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/users\/84"}],"replies":[{"embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/comments?post=7429"}],"version-history":[{"count":5,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/posts\/7429\/revisions"}],"predecessor-version":[{"id":7523,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/posts\/7429\/revisions\/7523"}],"wp:attachment":[{"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/media?parent=7429"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/categories?post=7429"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/tags?post=7429"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=7429"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}