list comprehension in python (with comparisons in javascript)

2020-06-11

 | 

~5 min read

 | 

994 words

Python has a very concise syntax for creating new lists called List Comprehension.

List comprehension is a way to define a new list based on an old one.

In this post I’ll:

  1. Discuss the syntax of List Comprehension
  2. Walk through some examples in Python
  3. Contrast it with Javascript

Syntax Breakdown

The syntax for a list defined with list comprehension has four pieces (some of which are optional):

  1. the result, e.g., new_list
  2. the expression, i.e. the new value based on the old list’s element, e.g., el
  3. the old list, e.g., for el in old_list
  4. an optional filter, e.g., if el != None

This looks like:

new_list = [el for el in old_list if el != None ]

NB: The expression must reference the variable used to to find elements in the old list. So while new_list = [el for el in old_list] is valid, new_list = [number for el in old_list] will throw an error. The same is true for the filter.

Python Example

First up, creating a list of odd numbers between 1 and 10 in Python.

We begin by constructing our base list:

>>> numbers = []
>>> for number in range(1,11):
... numbers.append(number)
...
>>> numbers
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Now we want to filter out odd numbers, we could use the same for loop strategy:

>>> odd_numbers = []
>>> for number in numbers:
...     if number % 2 != 0:
...             odd_numbers.append(number)
...
>>> odd_numbers
[1, 3, 5, 7, 9]

But list comprehension allows a more concise syntax:

>>> odd_numbers = [number for number in numbers if number % 2 != 0]
>>> odd_numbers
[1, 3, 5, 7, 9]

But what if we didn’t want to filter. Instead we wanted to transform - doubling each number in the list for example:

>>> doubles = [number * 2 for number in numbers]
>>> doubles
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

And now putting that together - filtering out the evens, and then tripling the remaining values:

>>> triple_odds = [number * 3 for number in numbers if number % 2 != 0]
>>> triple_odds
[3, 9, 15, 21, 27]

Now that we understand list comprehension, we can see that we could have created our first list more concisely too:

>>> numbers = [number for number in range(1,11)]
>>> numbers
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Before moving on, let’s look at those side-by-side to see how list comprehension mirrors the syntax of the for-loop / if-statement:

>>> numbers = [number for number in range(1,11)]
>>> numbers
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> triple_odd = [number * 3 for number in numbers if number % 2 != 0]
>>> triple_odd
[3, 9, 15, 21, 27]
>>> triple_odd = [] # reset the variable
>>> for number in numbers:
...     if number % 2 != 0:
...             triple_odd.append(number * 3)
...
>>> triple_odd
[3, 9, 15, 21, 27]

The expressions are almost identical, though the list comprehension is in one line:

  1. number * 3 is the expression in the list comprehension in the first position. It is the last thing to occur in our for/if statement.
  2. if number % 2 != 0 is the filter in the list comprehension (last position), and the middle place in the for/if statement.
  3. for number in numbers is the loop over the old list and is in the second position of our list comprehension and kicks off the for/if statement.

Now that we’ve seen how it’s done in Python, let’s take a look at how you might achieve similar results in Javascript.

Javascript Equivalent

One of the interesting things about learning a new language is to see how it compares to others.

Here, I’ll look at how I might achieve the same results of list comprehension with Javascript.

Javascript used to have array comprehension, but it’s been deprecated which means we’ll need a different strategy here.

We get a hint for how to approach this from the documentation on array comprehensions:

Comprehensions can often be used in place of calls to map() and filter() , or as a way of combining the two.

Since array comprehension was about combining maps and filters, we’ll likely be able to achieve the same results by combining those.

Let’s take a look at the same example above of creating a numbers array, then finding an odd numbers and a triple odd numbers list.

First, let’s be fancy and use Array.from() and it’s second argument, which is a map to generate our range of numbers 1-10.1

let numbers = Array.from(new Array(10), (_, i) => i + 1)
console.log(numbers) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Now, we can create a filter to get our odd numbers:

let oddNumbers = numbers.filter((num) => num % 2 !== 0)
console.log(oddNumbers) // [1, 3, 5, 7, 9]

And for our triple odd numbers:

let tripleOddNumbers = numbers
  .filter((num) => num % 2 !== 0)
  .map((odd) => odd * 3)
console.log(tripleOddNumbers) // [3, 9, 15, 21, 27]

In our case, the order actually does not matter, however filtering before mapping is slightly more efficient as we reduce the number of elements we’ll need to map over:

let tripleOddNumbers = numbers
  .map((number) => number * 3)
  .filter((number) => number % 2 !== 0)
console.log(tripleOddNumbers) // [3, 9, 15, 21, 27]

Footnotes

  • 1 I say fancy because generating prefilled arrays has always been something I’ve struggled with (though I’ve written about generating arrays here) - unless I use a for-loop, and this is the first time I’ve used the second argument from Array.from. This particular approach was inspired by Jason Yu’s article on Dev.To.

Related Posts
  • List Comprehension And Chunking In Python


  • Hi there and thanks for reading! My name's Stephen. I live in Chicago with my wife, Kate, and dog, Finn. Want more? See about and get in touch!