Posts tagged #for

the difference between the for comprehension and Enum.each

Look at the code below and try to guess what happens when you run the following lines of code.

for

for {:resp, f} <- [{:resp, 3}, :b, {:resp, 4}] do
  IO.inspect f
end

Enum.each

Enum.each([{:resp, 3}, :b, {:resp, 4}], fn {:resp, f} ->
  IO.inspect f
end)

The for version chugs along just fine :) which might surprise you. The Enum.map version blows up as expected.

Be careful about using for in your code, especially your tests. I had a small test which was the following lines:

assert length(stats) == 2
for {:resp, stat} <- stats do
  assert stat.meta == %{a: 3}
  assert stat.time_ms in 10..20
end

And this was passing every time even when I changed the assert to the code below.

for {:resp, stat} <- stats do
  assert stat.meta == nil
  assert stat.time_ms in 10..20
end

All because I had an incorrect pattern match. I had {:resp, stat} instead of a { {:resp, _id}, stat }. So, the for was filtering out all the stats and the inner block was not being executed even once.

How to create a Cartesian product of two sets

Elixir has a very rich set of functions to work with collections in the Enum module. The name Enum however, is a bit unfortunate. Enum makes me think of (enumerated data)[https://en.wikipedia.org/wiki/Enumerated_type] more than the enumerable.

Anyway, the other day I needed to compute the Cartesian product between to lists in my elixir app. And, I knew there would be something for that in the Enum module. I went through all the documentation and couldn’t find anything useful. That is when it hit me that comprehensions are best suited for this and this is a piece of cake for comprehensions.

So, without further ado, here is the code to get a Cartesian product in elixir:

a = [1, 2, 3, 4]
b = [1, 2, 3, 4]

cp = for x <- a, y <- b, do: {x, y}
IO.inspect(cp)
# =>
# [{1, 1}, {1, 2}, {1, 3}, {2, 1}, {2, 2}, {2, 3}, {3, 1}, {3, 2}, {3, 3}]