Since summer, I have two trainees. One very nice thing about that situation is that I am forced to think about basic concepts in a way I never did before – because now I have to explain and teach them instead of just using them.
And sometimes, I learn new terms – like “list comprehension”.
The term might be known by most Python developers, but I never encountered it so far and when my trainee brought it up I was curious.
Here’s what my current understanding of the concept is:
What is List Comprehension?
In short, list comprehension is a way in which a programming language supports working with lists and collections in a comfortable way.
In most programming languages, you are able to iterate through lists of objects and do all sorts of manipulations inside that iteration loop, for example creating a new list with just a part of the original content based on some conditions.
If a programming language supports list comprehension, it provides an easier way to do that.
Let’s look at an easy Python example where we have a list of dictionaries, holding some famous Star Wars Characters:
starWarsCharacters = (
{"name":"Darth Vader", "side":"dark"},
{"name":"Mace Windu", "side":"light"},
{"name":"Leia Organa", "side":"light"},
{"name":"Darth Maul", "side":"dark"},
)
newList = []
for i in range(0, len(starWarsCharacters)) :
if ( starWarsCharacters[i]["side"] == "dark") :
newList.append(starWarsCharacters[i]["name"])
print(newList)
I can use a for-loop to go through all the elements of a list and if they belong to the dark side, put their name into a new list.
Thanks to list comprehension in Python, I can do the same with one single line of code, which is also a lot easier to read:
newList = [character["name"] for character in starWarsCharacters if character["side"] == "dark"]
print(newList)
Isn’t that nice? It’s nearly self-explanatory, but let’s go through it step by step.
Anatomy of List Comprehension
List comprehension usually consists of 3 parts: A source from which to read, a filter (optional) and a mapping that goes into the new list.
In our Python example, the parts are as follows, put into square brackets:
Source | for character in starWarsCharacters |
Filter | if character["side"] == "dark" |
Mapping | character["name"] |
The order in which the different parts are arranged in Python is
<Mapping> for <SourceListElement> in <SourceList> if <Filter>
List Comprehension in Other Languages
I’m not sure if the term “list comprehension” is really used in other languages, but when I understood what the term means in Python I recognized that the concept exists in a lot of programming languages:
Python
starWarsCharacters = (
{"name":"Darth Vader", "side":"dark"},
{"name":"Mace Windu", "side":"light"},
{"name":"Leia Organa", "side":"light"},
{"name":"Darth Maul", "side":"dark"},
)
newList = [character["name"] for character in starWarsCharacters if character["side"] == "dark"]
print(newList)
# Run: py characters_of_the_dark_side.py
JavaScript
let starWarsCharacters = [
{name:"Darth Vader", side:"dark"},
{name:"Mace Windu", side:"light"},
{name:"Leia Organa", side:"light"},
{name:"Darth Maul", side:"dark"},
];
let newList =
starWarsCharacters
.filter(character => character.side == "dark")
.map(character => character.name);
console.log(newList);
// Run: node characters_of_the_dark_side.js
Note that the order in which the different list comprehension parts are arranged are different, but the way it works is pretty similar.
C#
To run C# code as script, install the dotnet-scripting tool via
dotnet tool install -g dotnet-script
or read about the alternatives.
var starWarsCharacters = new[] {
new {name = "Darth Vader", side = "dark"},
new {name = "Mace Windu", side = "light"},
new {name = "Leia Organa", side = "light"},
new {name = "Darth Maul", side = "dark"}
};
var newList =
from character in starWarsCharacters
where character.side == "dark"
select character.name;
foreach ( var item in newList ) {
Console.WriteLine(item);
}
// Run: dotnet script characters_of_the_dark_side.csx
The list comprehension feature of C# is called LINQ – and it’s quite awesome.
SQL
People often forget this, but SQL is really the champion of list comprehension.
To run this example you have to install sqlite, e.g. on Windows via chocolatey:
choco install sqlite
with starWarsCharacters as (
select "Darth Vader" name, "dark" side union all
select "Mace Windu" name, "light" side union all
select "Leia Organa" name, "light" side union all
select "Darth Maul" name, "dark" side
)
select character.name
from starWarsCharacters character
where side = "dark";
-- Run: sqlite3 test.db ".read characters_of_the_dark_side.sql"
Java
Philipp Salvisberg shared this awesome example in Java 15 (which I modified a tiny bit to fit into the exact example scheme).
To install Java 15 on windows, use
choco install openjdk
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class characters_of_the_dark_side {
public record Character(String name, String side) {};
public static void main(String[] args) {
var starwarsCharacters = Arrays.asList(
new Character("Darth Vader", "dark"),
new Character("Mace Windu", "light"),
new Character("Leia Organa", "light"),
new Character("Darth Maul", "dark")
);
var newList = starwarsCharacters
.stream()
.filter(character -> character.side.equals("light"))
.map(character -> character.name)
.collect(Collectors.toList());
System.out.println(newList);
}
}
// Run: java --enable-preview --source 15 characters_of_the_dark_side.java
Was this helpful and/or interesting? Let me know 🙂
2 Comments
Philipp Salvisberg · February 10, 2021 at 6:29 am
Nice blog post. I like how you demonstrate that C#Script and SQL are similar. Here’s an additional example using Java 15:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Demo {
public record Character(String name, String side) {};
public static void main(String[] args) {
List starwarsCharacters = Arrays.asList(
new Character(“Darth Vader”, “dark”),
new Character(“Mace Windu”, “light”),
new Character(“Leia Organa”, “light”),
new Character(“Darth Maul”, “dark”)
);
List newList = starwarsCharacters
.stream()
.filter(character -> character.side.equals(“light”))
.collect(Collectors.toList());
System.out.println(newList);
}
}
// Run: java –enable-preview –source 15 Demo.java
Sam · February 10, 2021 at 3:09 pm
Awesome! I included it with a tiny bit of modification to fit to the exact example scheme. Thanks a lot!