A repository of bitesize articles, tips & tricks
(in both English and French) curated by Mirego’s team.

We’re hiring!

Counting a mapped and filtered list with Elixir

Suppose we have a list of attribute maps and we want to do three things:

  1. Convert each attribute map to a specific result (by passing them to Foo.run/1)
  2. Filter out results we don’t want (we only want {:ok, _} results)
  3. Return how many results we’re left with

We can easily do this with Elixir Enum.map/2, Enum.filter/2 and Enum.count/1:

attrs_list
|> Enum.map(&Foo.run/1)
|> Enum.filter(fn result -> match?({:ok, _}, result) end)
|> Enum.count()

But we end up looping three times in the list. Could we reduce it to two? Sure!

attrs_list
|> Enum.filter(fn attrs ->
  result = Foo.run(attrs)
  match?({:ok, _}, result)
end)
|> Enum.count()

Instead of mapping first and filtering in a separate loop, we combine these two steps into one. But could we get down to a single loop? Yup!

Enum.reduce(attrs_list, 0, fn attrs, count ->
  result = Foo.run(attrs)
  if match?({:ok, _}, result), do: count + 1, else: count
end)

Elixir provides Enum.count/2 to do exactly that:

Enum.count(attrs_list, fn attrs ->
  result = Foo.run(attrs)
  match?({:ok, _}, result)
end)

It will map, filter and count the list — all in the same loop (instead of three)! 💥