Comprehensions

Learn about comprehension, its scope, and its returned values.

When we’re writing functional code, we often map and filter collections of things. To make our life easier (and our code easier to read), Elixir provides a general-purpose shortcut for this: the comprehension.

The idea of comprehension is fairly simple: given one or more collections, extract all combinations of values from each, optionally filter the values, and then generate a new collection using the remaining values.

The general syntax for comprehensions is deceptively simple: result = for generator or filter... [, into: value ], do: expression.

Let’s see a couple of basic examples before we get into the details.

iex> for x <- [ 1, 2, 3, 4, 5 ], do: x * x
[1, 4, 9, 16, 25]
iex> for x <- [ 1, 2, 3, 4, 5 ], x < 4, do: x * x 
[1, 4, 9]

A generator specifies how we want to extract values from a collection. Any variables matched in the pattern are available in the rest of the comprehension (including the block).

pattern <- enumerable_thing

For example, x <- [1,2,3] says that we want to first run the rest of the comprehension with x set to 1. Then, we run it with x set to 2, and so on. If we have two generators, their operations are nested. So, x <- [1,2], y <- [5,6] will run the rest of the comprehension with x=1, y=5; x=1, y=6; x=2, y=5; and x=2, y=6. We can use those values of x and y in the do block:

iex>for x<-[1,2],y<-[5,6],do: x*y 
[5, 6, 10, 12]

iex> for x <- [1,2], y <- [5,6], do: {x, y} 
[{1, 5}, {1, 6}, {2, 5}, {2, 6}]

For example, the code that follows uses a comprehension to list pairs of numbers from 1 to 8 whose product is a multiple of 10. It uses two generators to cycle through the pairs of numbers and two filters. The first filter allows only pairs in which the first number is at least the value of the second. The second filter checks to see if the product is a multiple of 10.

iex> first8 = [ 1,2,3,4,5,6,7,8 ]
[1, 2, 3, 4, 5, 6, 7, 8]
iex> for x <- first8, y <- first8, x >= y, rem(x*y, 10)==0, do: { x, y } 
[{5, 2}, {5, 4}, {6, 5}, {8, 5}]

This comprehension iterates 64 times, with x=1, y=1; x=1, y=2; and so on. However, the first filter cuts the iteration short when x is less than y. This means the second filter runs only 36 times.

Get hands-on with 1400+ tech skills courses.