Comprehensions in Elixir

Published October 18, 2018 by Toran Billups

In part 23 of my Elixir journey I wanted to show the comprehension syntax by example.

Comprehensions

I use map and filter together enough that I starting searching for a shorthand that offers both but in a more expressive syntax.

    Enum.filter([1, 2, 12], &(&1 < 10))
      |> Enum.map(&(&1 * 2))
  

I found comprehensions in Elixir offer a powerful and concise syntax to transform various data structures.

    for x <- [1, 2, 12], x < 10, do: x * 2
  

Lucky for me I did a good deal of python years ago so the syntax was vaguely familiar. If you are new to the idea, here is a conceptual look at what is happening.

for `generator`, `filter`, do: expression

The `generator` can be thought of as simply "how you extract data from the collection". Any variable you match here is then available to the entire comprehension including the block (ie: after the `do`). You can use the shorthand block syntax or expand to a more verbose block if necessary.

    for x <- [1, 2, 12], x < 10 do
      x * 2
    end
  

To get the result of the comprehension you simply bind a variable like you would any `Enum` function.

    result = for x <- [1, 2, 12], x < 10, do: x * 2
    total = Enum.reduce(result, 0, &(&1 + &2))
    IO.puts "total #{total}"
  

The filter is optional if that wasn't clear from the examples above.

    for x <- [1, 2, 12], do: x * 2
  

One example from the Elixir documentation that was worth duplicating shows how you would pattern match as part of the comprehension.

    numbers = [even: 2, odd: 3, even: 4, odd: 5, even: 6]
    for {:even, n} <- numbers, do: n * 2
  

The result of any comprehension is a list by default but you can alter the data structure returned by using `into`

    numbers = %{one: 1, two: 2, three: 3}
    for {key, val} <- numbers, into: %{}, do: {key, val * 2}
  

Buy Me a Coffee

Twitter / Github / Email