Suppose we have a list of attribute maps and we want to do three things:
Foo.run/1
){:ok, _}
results)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)! 💥