Last active
June 11, 2025 03:12
-
Star
(357)
You must be signed in to star a gist -
Fork
(35)
You must be signed in to fork a gist
-
-
Save bearfrieze/a746c6f12d8bada03589 to your computer and use it in GitHub Desktop.
Revisions
-
Bjørn Friese revised this gist
Apr 7, 2016 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -291,6 +291,6 @@ Thanks for reading this article. Let me know how you use comprehensions in the c - [Origami Yoda](http://origamiyoda.com/submission/star-wars-all-lightsaber-colors-and-meanings/) for their awesome list of light saber colors and jedis. - [Wookieepedia](http://starwars.wikia.com/wiki/Main_Page) for all sorts of Star Wars trivia. ## License <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">Comprehensions in Python the Jedi way</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://frieze.dk" property="cc:attributionName" rel="cc:attributionURL">Bjørn Friese</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">Creative Commons Attribution-ShareAlike 4.0 International License</a>. -
Bjørn Friese revised this gist
Apr 7, 2016 . 1 changed file with 6 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,5 +1,7 @@ # Comprehensions in Python the Jedi way by [Bjørn Friese](https://frieze.dk) > Beautiful is better than ugly. > Explicit is better than implicit. @@ -288,3 +290,7 @@ Thanks for reading this article. Let me know how you use comprehensions in the c - [Thomas Dybdahl Ahle](https://github.com/thomasahle) and [Andreas Bruun Okholm](https://dk.linkedin.com/in/andreas-okholm-9474b14b) for thorough reviews and inspiration. - [Origami Yoda](http://origamiyoda.com/submission/star-wars-all-lightsaber-colors-and-meanings/) for their awesome list of light saber colors and jedis. - [Wookieepedia](http://starwars.wikia.com/wiki/Main_Page) for all sorts of Star Wars trivia. --- <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">Comprehensions in Python the Jedi way</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://frieze.dk" property="cc:attributionName" rel="cc:attributionURL">Bjørn Friese</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">Creative Commons Attribution-ShareAlike 4.0 International License</a>. -
Bjørn Friese revised this gist
Mar 27, 2016 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -70,13 +70,13 @@ Hmm, that looks promising, but it's still kind of fragmented. What if we removed Normally we would [`filter`](https://docs.python.org/3/library/functions.html#filter) out all the `' '` characters: ```python chrs = list(filter(lambda c: c != ' ', chrs)) ``` That would work, but now that we know the true power of the comprehension, we can simply do this instead: ```python chrs = [c for c in chrs if c != ' '] ``` We can use `if` clauses in our list comprehensions to perform a filtering operations. Neat! -
Bjørn Friese revised this gist
Mar 27, 2016 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -273,6 +273,8 @@ print(frequencies) This approach uses an additional line to create a list of colors, but on the other hand it's easy to understand what's going on without reading the `Counter` documentation. > Note: The solution with comprehensions run in quadratic time while `collections.Counter` runs in linear time. If you need to do this efficiently use `collections.Counter`. ## That's all I hope you feel like you now got a comprehensive overview of comprehensions. I urge you to give them a test drive if you haven't already. -
Bjørn Friese revised this gist
Mar 27, 2016 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -5,7 +5,7 @@ -- <cite>[The Zen of Python](https://www.python.org/dev/peps/pep-0020/)</cite> I frequently deal with collections of things in the programs I write. Collections of droids, jedis, planets, lightsabers, starfighters, etc. When programming in Python, these collections of things are usually represented as lists, sets and dictionaries. Oftentimes, what I want to do with collections is to transform them in various ways. Comprehensions is a powerful syntax for doing just that. I use them extensively, and it's one of the things that keep me coming back to Python. Let me show you a few examples of the incredible usefulness of comprehensions. All of the tasks presented in the examples can be accomplished with the extensive standard library available in Python. These solutions would arguably be more terse and efficient in some cases. I don't have anything against the standard library. To me there is a certain elegance and beauty in the explicit nature of comprehensions. Everything you need to know is right there in the code in a concise and readable form – no need to dig through the docs. -
Bjørn Friese revised this gist
Mar 27, 2016 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -277,7 +277,7 @@ This approach uses an additional line to create a list of colors, but on the oth I hope you feel like you now got a comprehensive overview of comprehensions. I urge you to give them a test drive if you haven't already. Thanks for reading this article. Let me know how you use comprehensions in the comments section.  -
Bjørn Friese revised this gist
Mar 27, 2016 . 1 changed file with 4 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -279,9 +279,10 @@ I hope you feel like you now got a comprehensive overview of comprehensions. I u Let me know how you use comprehensions in the comments section.  ## Thanks - [Thomas Dybdahl Ahle](https://github.com/thomasahle) and [Andreas Bruun Okholm](https://dk.linkedin.com/in/andreas-okholm-9474b14b) for thorough reviews and inspiration. - [Origami Yoda](http://origamiyoda.com/submission/star-wars-all-lightsaber-colors-and-meanings/) for their awesome list of light saber colors and jedis. - [Wookieepedia](http://starwars.wikia.com/wiki/Main_Page) for all sorts of Star Wars trivia. -
Bjørn Friese revised this gist
Mar 27, 2016 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -182,7 +182,7 @@ print(['{[name]} → {[model]}'.format(p, s) for p, s in pilot_ships]) Ready for lift-off!  ## Planets -
Bjørn Friese revised this gist
Mar 27, 2016 . 1 changed file with 12 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -171,7 +171,18 @@ No problem, we just join the two lists using a nested list comprehension: pilot_ships = [(p, s) for p in pilots for s in ships if p['ship_id'] == s['id']] ``` For each pilot we iterate over all the ships. If the pilots `ship_id` is equal to the ships `id` they are a match, and we add the tuple to the list. Let's see if we got this right: ```python print(['{[name]} → {[model]}'.format(p, s) for p, s in pilot_ships]) # ['Luke Skywalker → T-65B X-wing', 'Darth Vader → TIE Advanced x1'] ``` Ready for lift-off!  ## Planets -
Bjørn Friese revised this gist
Mar 27, 2016 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -5,7 +5,7 @@ -- <cite>[The Zen of Python](https://www.python.org/dev/peps/pep-0020/)</cite> I frequently deal with collections of things in the programs I write. Collections of droids, jedis, planets, lightsabers, star fighters, etc. When programming in Python, these collections of things are usually represented as lists, sets and dictionaries. Oftentimes, what I want to do with collections is to transform them in various ways. Comprehensions is a powerful syntax for doing just that. I use them extensively, and it's one of the things that keep me coming back to Python. Let me show you a few examples of the incredible usefulness of comprehensions. All of the tasks presented in the examples can be accomplished with the extensive standard library available in Python. These solutions would arguably be more terse and efficient in some cases. I don't have anything against the standard library. To me there is a certain elegance and beauty in the explicit nature of comprehensions. Everything you need to know is right there in the code in a concise and readable form – no need to dig through the docs. @@ -213,7 +213,7 @@ Set comprehensions!  ## Lightsabers I recently stumbled upon the [`collections.Counter`](https://docs.python.org/3/library/collections.html#collections.Counter) class while reading some code a friend had written. He was using it to buld a dictionary of frequencies of certain values appearing in a list of dictionaries roughly like this: -
Bjørn Friese revised this gist
Mar 27, 2016 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -206,7 +206,7 @@ planets_set = set(planets_flat) But we won't bother with that. We got a secret weapon that will simplify and obliterate this task: ```python planets_set = {planet for episode in episodes.values() for planet in episode['planets']} ``` Set comprehensions! -
Bjørn Friese revised this gist
Mar 27, 2016 . 1 changed file with 24 additions and 12 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -139,6 +139,13 @@ Finally, we might want to score these matches based on whether the droids share scores = ['Great' if a['fav_jedi'] == b['fav_jedi'] else 'Miserable' for a, b in matches] ``` Let's zip the matches with the scores and print them in a nice and readable format: ```python print(['{[name]} + {[name]} = {}'.format(*m, s) for m, s in zip(matches, scores)]) # ['BB-8 + R2-D2 = Miserable', 'BB-8 + C-3PO = Miserable', 'R2-D2 + C-3PO = Great'] ``` And thus we can conclude that R2-D2 and C-3PO are a great match.  @@ -168,26 +175,28 @@ For each pilot we iterate over all the ships. If the pilots `ship_id` is equal t ## Planets We are presented with a dictionary of episodes each containing a (non-exhaustive) list of names of planets that appears in that episode: ```python episodes = { 'Episode I': {'planets': ['Naboo', 'Tatooine', 'Coruscant']}, 'Episode II': {'planets': ['Geonosis', 'Kamino', 'Geonosis']}, 'Episode III': {'planets': ['Felucia', 'Utapau', 'Coruscant', 'Mustafar']}, 'Episode IV': {'planets': ['Tatooine', 'Alderaan', 'Yavin 4']}, 'Episode V': {'planets': ['Hoth', 'Dagobah', 'Bespin']}, 'Episode VI': {'planets': ['Tatooine', 'Endor']}, 'Episode VII': {'planets': ['Jakku', 'Takodana', 'Ahch-To']}, } ``` How can we get a collection of unique planets that appeared throughout the episodes? First we use a nested list comprehension to flatten the planets into a single list: ```python planets_flat = [planet for episode in episodes.values() for planet in episode['planets']] ``` > Note: The nested comprehension is consumed from left to right, and thus we need to have the episodes loop _before_ the planets loop. From here we could wrap the resulting list in a set like this to remove the duplicates: ```python @@ -244,6 +253,9 @@ But do we really need to import a class and read the documentation for said clas ```python colors = [jedi['lightsaber_color'] for jedi in jedis] frequencies = {color: colors.count(color) for color in set(colors)} print(frequencies) # {'green': 6, 'red': 5, 'blue': 6} ```  @@ -257,7 +269,7 @@ I hope you feel like you now got a comprehensive overview of comprehensions. I u Let me know how you use comprehensions in the comments section. Thanks: - [Thomas Dybdahl Ahle](https://github.com/thomasahle) and [Andreas Bruun Okholm](https://dk.linkedin.com/in/andreas-okholm-9474b14b) for thorough reviews and inspiration. - [Origami Yoda](http://origamiyoda.com/submission/star-wars-all-lightsaber-colors-and-meanings/) for their awesome list of light saber colors and jedis. - [Wookieepedia](http://starwars.wikia.com/wiki/Main_Page) for all sorts of Star Wars trivia. -
Bjørn Friese revised this gist
Mar 27, 2016 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -259,5 +259,6 @@ Let me know how you use comprehensions in the comments section. Thanks: - [Thomas Dybdahl Ahle](https://github.com/thomasahle) for review and inspiration. - [Origami Yoda](http://origamiyoda.com/submission/star-wars-all-lightsaber-colors-and-meanings/) for their awesome list of light saber colors and jedis. - [Wookieepedia](http://starwars.wikia.com/wiki/Main_Page) for all sorts of Star Wars trivia.  -
Bjørn Friese revised this gist
Mar 27, 2016 . 1 changed file with 34 additions and 11 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -18,7 +18,7 @@ All of the tasks presented in the examples can be accomplished with the extensiv We are trying to have a meaningful conversation with R2-D2, but he just bleeps and bloops in a seemingly random pattern. After scratching our head for a while, we start jotting down the sequence of bleeps `0` and bloops `1`: ```python bbs = '01110011001000000110111001101111001000000010000001101001001000000111001101101110001000000110010100100000001000000110100000100000001000000110010100100000011100100010000000100000011100000110110100100000011011110010000001100011' ``` Hmm. That looks interesting. Maybe it's octets of bits denoting ASCII characters? Let's try splitting up the bit string into octets. @@ -59,14 +59,41 @@ Now that we know what a list comprehension is, we can use it again to turn the o chrs = [chr(int(octet, 2)) for octet in octets] ``` And we get: ```python ['s', ' ', 'n', 'o', ' ', ' ', 'i', ' ', 's', 'n', ' ', 'e', ' ', ' ', 'h', ' ', ' ', 'e', ' ', 'r', ' ', ' ', 'p', 'm', ' ', 'o', ' ', 'c'] ``` Hmm, that looks promising, but it's still kind of fragmented. What if we removed the spaces? Normally we would [`filter`](https://docs.python.org/3/library/functions.html#filter) out all the `' '` characters: ```python chrs = list(filter(lambda c: c is not ' ', chrs)) ``` That would work, but now that we know the true power of the comprehension, we can simply do this instead: ```python chrs = [c for c in chrs if c is not ' '] ``` We can use `if` clauses in our list comprehensions to perform a filtering operations. Neat! Finally we join up the letters into a string to make the message more readable: ```python message = ''.join(chrs) ``` Err, what is a "snoisneherpmoc"? Maybe R2-D2 spoke the message in reverse for some reason. ```python message = ''.join(reversed(chrs)) ``` Ah! The message is "comprehensions". R2-D2 knows what's up. ## Droid dating @@ -118,7 +145,7 @@ And thus we can conclude that R2-D2 and C-3PO are a great match. ## Lift-off Darth Vader and Luke Skywalker can't find their ships right before the big chase around the Death Star. Let's help them out. ```python pilots = [ @@ -137,7 +164,7 @@ No problem, we just join the two lists using a nested list comprehension: pilot_ships = [(p, s) for p in pilots for s in ships if p['ship_id'] == s['id']] ``` For each pilot we iterate over all the ships. If the pilots `ship_id` is equal to the ships `id` they are a match, and we keep the touple in the list. ## Planets @@ -217,9 +244,6 @@ But do we really need to import a class and read the documentation for said clas ```python colors = [jedi['lightsaber_color'] for jedi in jedis] frequencies = {color: colors.count(color) for color in set(colors)} ```  @@ -235,6 +259,5 @@ Let me know how you use comprehensions in the comments section. Thanks: - [Thomas Dybdahl Ahle](https://github.com/thomasahle) for review and inspiration. - [Origami Yoda](http://origamiyoda.com/submission/star-wars-all-lightsaber-colors-and-meanings/) for their awesome list of light saber colors and jedis.  -
Bjørn Friese revised this gist
Mar 27, 2016 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -235,5 +235,6 @@ Let me know how you use comprehensions in the comments section. Thanks: - [Thomas Dybdahl Ahle](https://github.com/thomasahle) for review and inspiration. - [Origami Yoda](http://origamiyoda.com/submission/star-wars-all-lightsaber-colors-and-meanings/) for their awesome list of light saber colors and jedis. - [Wookieepedia](http://starwars.wikia.com/wiki/Main_Page) for all sorts of Star Wars trivia.  -
Bjørn Friese revised this gist
Mar 27, 2016 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -134,10 +134,10 @@ ships = [ No problem, we just join the two lists using a nested list comprehension: ```python pilot_ships = [(p, s) for p in pilots for s in ships if p['ship_id'] == s['id']] ``` For each pilot we iterate over all the ships. If the pilots `ship_id` equals the ships `id` they are a match, and we keep the touple in the list. ## Planets -
Bjørn Friese revised this gist
Mar 27, 2016 . No changes.There are no files selected for viewing
-
Bjørn Friese revised this gist
Mar 26, 2016 . 1 changed file with 120 additions and 42 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,107 +1,183 @@ # Comprehensions in Python the Jedi way > Beautiful is better than ugly. > Explicit is better than implicit. -- <cite>[The Zen of Python](https://www.python.org/dev/peps/pep-0020/)</cite> I frequently deal with collections of things in the programs I write. Collections of droids, jedis, planets, etc. When programming in Python, these collections of things are usually represented as lists, sets and dictionaries. Oftentimes, what I want to do with collections is to transform them in various ways. Comprehensions is a powerful syntax for doing just that. I use them extensively, and it's one of the things that keep me coming back to Python. Let me show you a few examples of the incredible usefulness of comprehensions. All of the tasks presented in the examples can be accomplished with the extensive standard library available in Python. These solutions would arguably be more terse and efficient in some cases. I don't have anything against the standard library. To me there is a certain elegance and beauty in the explicit nature of comprehensions. Everything you need to know is right there in the code in a concise and readable form – no need to dig through the docs. > Note: I'm using Python 3.5. List, set, and dictionary comprehensions are available in Python 2.7 and above, but the functions and syntax used in the examples might not be available/valid for other versions of Python. ## Bleeps and bloops  We are trying to have a meaningful conversation with R2-D2, but he just bleeps and bloops in a seemingly random pattern. After scratching our head for a while, we start jotting down the sequence of bleeps `0` and bloops `1`: ```python bbs = '0110001101101111011011010111000001110010011001010110100001100101011011100111001101101001011011110110111001110011' ``` Hmm. That looks interesting. Maybe it's octets of bits denoting ASCII characters? Let's try splitting up the bit string into octets. Using an imperative approach that might look something like this: ```python octets = [] for i in range(0, len(bbs), 8): octets.append(bbs[i:i+8]) ``` First initialize a new list. For every 8th index in the string we slice a string of length 8 and append it to the list of octets. Can we do better than this? Of course we can! Take a look at this functional approach: ```python octets = list(map(lambda i: bbs[i:i+8], range(0, len(bbs), 8))) ``` We [`map`](https://docs.python.org/3/library/functions.html#map) the indexes of the octets to a lambda function that return an octet starting at that index. The `map` function returns an iterable which we turn into a list with the [`list`](https://docs.python.org/3/library/functions.html#func-list) function. This is slightly more concise than the imperative approach, but arguably less readable. We decide to ask master Yoda for advice. He suggests the following: ```python octets = [bbs[i:i+8] for i in range(0, len(bbs), 8)] ``` Wait, is that the force? Nope, that right there is a comprehension. A list comprehension to be more exact. The brackets `[]` indicate that we are making a new list. Inside the brackets we first have an expression: `bbs[i:i+8]`. Next up is a `for` clause: `for i in range(0, len(bbs), 8)`. The `for` clause defines the iterator that we use as a basis for our new list, and the initial expression defines the resulting element in the new list. > Bonus info: The stuff inside the brackets is called a [generator expression](https://www.python.org/dev/peps/pep-0289/) and can be used on it's own to create iterators. Now that we know what a list comprehension is, we can use it again to turn the octets into characters: ```python chrs = [chr(int(octet, 2)) for octet in octets] ``` Finally we can join the letters into a string and print them: ```python print(''.join(chrs)) # 'comprehensions' ``` Ah, The message is "comprehensions"! Even R2-D2 knows what's up. ## Droid dating For this example we are making a dating service for heroic droids. We want a list of all the ways to match up 2 droids from the following list: ```python droids = [ {'name': 'BB-8', 'fav_jedi': 'Rey'}, {'name': 'R2-D2', 'fav_jedi': 'Luke Skywalker'}, {'name': 'C-3PO', 'fav_jedi': 'Luke Skywalker'}, ] ``` We could use [`itertools.combinations`](https://docs.python.org/3/library/itertools.html#itertools.combinations) to do this, but for now let's imagine it doesn't exist and that we have to write our own code for once. Let's start out by creating a list of all the possible permutations of 2 droids the old school way: ```python matches = [] for i in range(len(droids)): for j in range(i + 1, len(droids)): matches.append((droids[i], droids[j])) ``` We can make that a little nicer if we use the built in [`enumerate`](https://docs.python.org/3/library/functions.html#enumerate) function and some list slicing: ```python matches = [] for i, a in enumerate(droids): for b in droids[i + 1:]: matches.append((a, b)) ``` That can be turned into a cute one liner with a nested list comprehension (yes, you can nest them!): ```python matches = [(a, b) for i, a in enumerate(droids) for b in droids[i + 1:]] ``` Finally, we might want to score these matches based on whether the droids share a favourite jedi. This just happens to be really easy to do with an inline conditional expression: ```python scores = ['Great' if a['fav_jedi'] == b['fav_jedi'] else 'Miserable' for a, b in matches] ``` And thus we can conclude that R2-D2 and C-3PO are a great match.  ## Lift-off Darth Vader and Luke Skywalker can't find their ships right the big chase around the Death Star. Let's help them out. ```python pilots = [ {'name': 'Luke Skywalker', 'ship_id': 0}, {'name': 'Darth Vader', 'ship_id': 1}, ] ships = [ {'id': 0, 'model': 'T-65B X-wing'}, {'id': 1, 'model': 'TIE Advanced x1'}, ] ``` No problem, we just join the two lists using a nested list comprehension: ```python pilot_ships = [(p, s) for p in pilots for s in ships if p['ship_id'] is s['id']] ``` For each pilot we iterate over all the ships. If the pilots `ship_id` is that same as the ships `id` they are a match, and we keep the touple in the list. ## Planets We are presented with a dictionary of lists each containing a (non-exhaustive) list of names of planets that appears in a given episode: ```python planets = { 'Episode I': ['Naboo', 'Tatooine', 'Coruscant'], 'Episode II': ['Geonosis', 'Kamino', 'Geonosis'], 'Episode III': ['Felucia', 'Utapau', 'Coruscant', 'Mustafar'], 'Episode IV': ['Tatooine', 'Alderaan', 'Yavin 4'], 'Episode V': ['Hoth', 'Dagobah', 'Bespin'], 'Episode VI': ['Tatooine', 'Endor'], 'Episode VII': ['Jakku', 'Takodana', 'Ahch-To'], } ``` How can we get a collection of unique planets that appeared throughout the episodes? First we use a nested list comprehension to flatten the dictionary of lists into a single list: ```python planets_flat = [planet for planets in planets.values() for planet in planets] ``` From here we could wrap the resulting list in a set like this to remove the duplicates: ```python planets_set = set(planets_flat) ``` But we won't bother with that. We got a secret weapon that will simplify and obliterate this task: ```python planets_set = {planet for planets in planets.values() for planet in planets} ``` Set comprehensions!  ## Counting lightsabers I recently stumbled upon the [`collections.Counter`](https://docs.python.org/3/library/collections.html#collections.Counter) class while reading some code a friend had written. He was using it to buld a dictionary of frequencies of certain values appearing in a list of dictionaries roughly like this: @@ -136,7 +212,7 @@ print(frequencies) I thought that was a really cool solution. Note that we are using a generator expression here rather than a list comprehension, since we don't need the list (`Counter` takes an iterable which is exactly what you get from a generator expression). But do we really need to import a class and read the documentation for said class to accomplish this? No! Dictionary comprehensions can do this: ```python colors = [jedi['lightsaber_color'] for jedi in jedis] @@ -146,7 +222,7 @@ print(frequencies) # {'blue': 6, 'green': 6, 'red': 5} ```  This approach uses an additional line to create a list of colors, but on the other hand it's easy to understand what's going on without reading the `Counter` documentation. @@ -159,3 +235,5 @@ Let me know how you use comprehensions in the comments section. Thanks: - [Thomas Dybdahl Ahle](https://github.com/thomasahle) for review and inspiration. - [Origami Yoda](http://origamiyoda.com/submission/star-wars-all-lightsaber-colors-and-meanings/) for their awesome list of light saber colors and jedis.  -
Bjørn Friese revised this gist
Mar 26, 2016 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,7 +1,7 @@ # Master comprehensions in Python like a Jedi > Beautiful is better than ugly. > Explicit is better than implicit. -- <cite>[The Zen of Python](https://www.python.org/dev/peps/pep-0020/)</cite> -
Bjørn Friese revised this gist
Mar 26, 2016 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,7 +1,7 @@ # Master comprehensions in Python like a Jedi > Beautiful is better than ugly. Explicit is better than implicit. -- <cite>[The Zen of Python](https://www.python.org/dev/peps/pep-0020/)</cite> -
Bjørn Friese revised this gist
Mar 26, 2016 . 1 changed file with 1 addition and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -7,8 +7,7 @@ I frequently deal with collections of things in the programs I write. Collections of numbers, strings, jedis, etc. When programming in Python, these collections of things are usually represented as lists, sets and dictionaries. Oftentimes, what I want to do with collections is to filter and transform them in various ways. Comprehensions are powerful, concise, and allows us to do just that. I use them extensively, and it's one of the things that keep me coming back to Python. Let me show you a few examples of the incredible usefulness of comprehensions. All of the tasks presented in the examples can be accomplished with the extensive standard library available in Python. These solutions will often be more terse and effecient. I don't have anything against the standard library. To me there is a certain elegance and beauty in the explicit nature of comprehensions. Everything you need to know is right there in the code in a concise and readable form – no need to dig through the docs. > Note: I'm using Python 3.5. List, set, and dictionary comprehensions are available in Python 2.7 and above, but the functions and syntax used in the examples might not be available/valid for other versions of Python. -
Bjørn Friese revised this gist
Mar 26, 2016 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -9,6 +9,7 @@ I frequently deal with collections of things in the programs I write. Collection > Some of these examples can be solved very elegantly (and more effeciently) using the extensive standard library available in Python. I don't have anything against the standard library, but comprehensions often seem more beautiful and explicit to me compared to the standard library. Everything you need to know is right there in the code in a concise and readable form – no need to dig through the docs. > Note: I'm using Python 3.5. List, set, and dictionary comprehensions are available in Python 2.7 and above, but the functions and syntax used in the examples might not be available/valid for other versions of Python. ## Filtering and mapping -
Bjørn Friese revised this gist
Mar 26, 2016 . 1 changed file with 11 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,13 @@ # Master comprehensions in Python like a Jedi > Beautiful is better than ugly. > Explicit is better than implicit. -- <cite>[The Zen of Python](https://www.python.org/dev/peps/pep-0020/)</cite> I frequently deal with collections of things in the programs I write. Collections of numbers, strings, jedis, etc. When programming in Python, these collections of things are usually represented as lists, sets and dictionaries. Oftentimes, what I want to do with collections is to filter and transform them in various ways. Comprehensions are powerful, concise, and allows us to do just that. I use them extensively, and it's one of the things that keep me coming back to Python. Let me show you a few examples of the incredible usefulness of comprehensions. > Some of these examples can be solved very elegantly (and more effeciently) using the extensive standard library available in Python. I don't have anything against the standard library, but comprehensions often seem more beautiful and explicit to me compared to the standard library. Everything you need to know is right there in the code in a concise and readable form – no need to dig through the docs. > Note: I'm using Python 3.5. List, set, and dictionary comprehensions are available in Python 2.7 and above, but the functions and syntax used in the examples might not be available/valid for other versions of Python. @@ -149,4 +156,6 @@ I hope you feel like you now got a comprehensive overview of comprehensions. I u Let me know how you use comprehensions in the comments section. Thanks: - [Thomas Dybdahl Ahle](https://github.com/thomasahle) for review and inspiration. - [Origami Yoda](http://origamiyoda.com/submission/star-wars-all-lightsaber-colors-and-meanings/) for their awesome list of light saber colors and jedis. -
Bjørn Friese revised this gist
Mar 26, 2016 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -60,7 +60,7 @@ Perfect! We map and filter in a single line without making a mess. ## Combinations For this example, we want to get all the combinations of 2 numbers previous example. In other words, we want a set of sets where each set represents a way to pick out 2 numbers from the list of numbers. Normally I would use [`itertools.combinations`](https://docs.python.org/3/library/itertools.html#itertools.combinations) to do this, but let's imagine it doesn't exist for the duration of this example. Let's start out by creating a list of all the possible permutations of 2 numbers the old school way: @@ -141,7 +141,7 @@ print(frequencies)  This approach uses an additional line to create a list of colors, but on the other hand it's easy to understand what's going on without reading the `Counter` documentation. ## That's all -
Bjørn Friese revised this gist
Mar 26, 2016 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,4 @@ # Master comprehensions in Python like a Jedi Much of the programming I do deals with collections of things. In Python, these collections of things are usually represented as lists, sets and dictionaries. Oftentimes, what I want to do with collections is to filter and transform them in various ways. Comprehensions are powerful, concise, and allows us to do just that. I use them extensively, and it's one of the things that keep me coming back to Python. Let me show you the incredible usefulness of comprehensions. -
Bjørn Friese revised this gist
Mar 26, 2016 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -139,7 +139,7 @@ print(frequencies) # {'blue': 6, 'green': 6, 'red': 5} ```  This approach uses an additional line to create a list of colors, but on the other hand it's crystal clear what's going on without reading the `Counter` documentation. -
Bjørn Friese revised this gist
Mar 26, 2016 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -139,7 +139,7 @@ print(frequencies) # {'blue': 6, 'green': 6, 'red': 5} ```  This approach uses an additional line to create a list of colors, but on the other hand it's crystal clear what's going on without reading the `Counter` documentation. -
Bjørn Friese revised this gist
Mar 26, 2016 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -147,6 +147,6 @@ This approach uses an additional line to create a list of colors, but on the oth I hope you feel like you now got a comprehensive overview of comprehensions. I urge you to give them a test drive if you haven't already. Let me know how you use comprehensions in the comments section. Thanks to [Origami Yoda](http://origamiyoda.com/submission/star-wars-all-lightsaber-colors-and-meanings/) for their awesome list of light saber colors and jedis. -
Bjørn Friese created this gist
Mar 26, 2016 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,152 @@ # Using comprehensions in Python like a Jedi Much of the programming I do deals with collections of things. In Python, these collections of things are usually represented as lists, sets and dictionaries. Oftentimes, what I want to do with collections is to filter and transform them in various ways. Comprehensions are powerful, concise, and allows us to do just that. I use them extensively, and it's one of the things that keep me coming back to Python. Let me show you the incredible usefulness of comprehensions. > Note: I'm using Python 3.5. List, set, and dictionary comprehensions are available in Python 2.7 and above, but the functions and syntax used in the examples might not be available/valid for other versions of Python. ## Filtering and mapping We have a list of random numbers in the interval `[1, 20]`: ```python ns = [10, 19, 6, 17, 9, 14, 3, 8, 15, 4] ``` We would like to create a new list that contains all numbers in the original list larger than 10: `[19, 17, 14, 15]`. An imperative approach could look like this: ```python rs = [] for n in ns: if n > 10: rs.append(n) ``` First initialize a new list. Then we iterate over all the numbers and append them to the new list if they are larger than 10. Now `rs` contains all the numbers larger than 10. Can we do better than this? Of course we can! Take a look at this functional approach: ```python rs = list(filter(lambda n: n > 10, ns)) ``` We [`filter`](https://docs.python.org/3/library/functions.html#filter) the list of numbers with a lambda function that takes a number and evaluates to true if the number is larger than 10. The `filter` function return an iterable which we turn into a list with the [`list`](https://docs.python.org/3/library/functions.html#func-list) function. This is more concise and easier to reason about than the imperative approach. But wait, there is more! Enter list comprehensions: ```python rs = [n for n in ns if n > 10] ``` That's more like it! The brackets `[]` clearly indicate that we are making a new list. Inside the brackets we first have an expression: `n`. Next up is a `for` clause: `n for n in ns`. Finally we have an `if` clause: `if n > 10`. The `for` clause defines the iterator that we use as a basis for our new list, the initial expression defines the resulting element in the new list, and the `if` clause filters the elements in the `for` clause based on the boolean expression we give it (in this case `n > 10`). > Bonus info: The stuff inside the brackets is called a [generator expression](https://www.python.org/dev/peps/pep-0289/) and can be used on it's own to create iterators. Now, let's say we wanted to multiply all the numbers in the resulting list by 42. Using a functional approach it could look like this: ```python rs = list(map(lambda n: n * 42, filter(lambda n: n > 10, ns))) ``` Ew! That's not very readable. The nested function calls and lambdas introduce a fair bit of noise. List comprehensions to the rescue! Due to the flexibility of list comprehensions, we can combine [`map`](https://docs.python.org/3/library/functions.html#map) and `filter` operations in a concise and readable way: ```python rs = [n * 42 for n in ns if n > 10] ``` Perfect! We map and filter in a single line without making a mess. ## Combinations For this example, we want to get all the combinations of 2 numbers previous example. In other words, we want a set of sets where each set represents a way to pick out 2 numbers from the list of numbers. Let's start out by creating a list of all the possible permutations of 2 numbers the old school way: ```python cs = [] for i in range(len(ns)): for j in range(i + 1, len(ns)): cs.append((ns[i], ns[j])) ``` We can make that a little nicer if we use the built in [`enumerate`](https://docs.python.org/3/library/functions.html#enumerate) function and some list slicing: ```python cs = [] for i, a in enumerate(ns): for b in ns[i + 1:]: cs.append((a, b)) ``` ...and we can turn that into a cute one liner with a nested list comprehension (yes, you can nest them!): ```python cs = [(a, b) for i, a in enumerate(ns) for b in ns[i + 1:]] ``` Finally, to get the combinations we do the same, except with sets this time (yes, you can do set comprehensions!): ```python cs = {frozenset({a, b}) for i, a in enumerate(ns) for b in ns[i + 1:]} ``` Boom! Note that we had to use [frozen sets](https://docs.python.org/3/library/stdtypes.html#set-types-set-frozenset) (immutable sets), since regular sets aren't hashable in Python and thus aren't allowed in sets. ## Frequencies I recently stumbled upon the [`collections.Counter`](https://docs.python.org/3/library/collections.html#collections.Counter) class while reading some code a friend had written. He was using it to buld a dictionary of frequencies of certain values appearing in a list of dictionaries roughly like this: ```python import collections jedis = [ {'name': 'Ahsoka Tano', 'lightsaber_color': 'green'}, {'name': 'Anakin Skywalker', 'lightsaber_color': 'blue'}, {'name': 'Anakin Solo', 'lightsaber_color': 'blue'}, {'name': 'Ben Skywalker', 'lightsaber_color': 'blue'}, {'name': 'Count Duku', 'lightsaber_color': 'red'}, {'name': 'Darth Craidus', 'lightsaber_color': 'red'}, {'name': 'Darth Maul', 'lightsaber_color': 'red'}, {'name': 'Darth Vader', 'lightsaber_color': 'red'}, {'name': 'Jacen Solo', 'lightsaber_color': 'green'}, {'name': 'Ki-Adi-Mundi', 'lightsaber_color': 'blue'}, {'name': 'Kit Fisto', 'lightsaber_color': 'green'}, {'name': 'Luke Skywalker', 'lightsaber_color': 'green'}, {'name': 'Obi-Wan Kenobi', 'lightsaber_color': 'blue'}, {'name': 'Palpatine', 'lightsaber_color': 'red'}, {'name': 'Plo-Koon', 'lightsaber_color': 'blue'}, {'name': 'Qui-Gon Jinn', 'lightsaber_color': 'green'}, {'name': 'Yoda', 'lightsaber_color': 'green'}, ] frequencies = collections.Counter(jedi['lightsaber_color'] for jedi in jedis) print(frequencies) # Counter({'blue': 6, 'green': 6, 'red': 5}) ``` I thought that was a really cool solution. Note that we are using a generator expression here rather than a list comprehension, since we don't need the list (`Counter` takes an iterable which is exactly what you get from a generator expression). But do we really need to import a class and read the documentation for said class to accomplish this? No! Dictionary comprehensions to the rescue: ```python colors = [jedi['lightsaber_color'] for jedi in jedis] frequencies = {color: colors.count(color) for color in set(colors)} print(frequencies) # {'blue': 6, 'green': 6, 'red': 5} ```  This approach uses an additional line to create a list of colors, but on the other hand it's crystal clear what's going on without reading the `Counter` documentation. ## That's all I hope you feel like you now got a comprehensive overview of comprehensions. I urge you to give them a test drive if you haven't already. Let me now how you use comprehensions in the comments section. Thanks to [Origami Yoda](http://origamiyoda.com/submission/star-wars-all-lightsaber-colors-and-meanings/) for their awesome list of light saber colors and jedis.