Reputation: 1110
I'm trying to understand capture operator and where it can be used. Here is working example:
%{name: "Daniel", dob: 2016, email: "[email protected]"}
|> Enum.filter(fn({_k, v}) -> is_binary(v) end)
|> Enum.into(%{})
which returns
%{email: "[email protected]", name: "Daniel"} .
Now I'm trying to use capture operator inside Enum.filter/2 where I'm using the second element from map pair.
%{name: "Daniel", dob: 2016, email: "[email protected]"}
|> Enum.filter(&is_binary(&2))
|> Enum.into(%{})
and the iex console says
** (CompileError) iex:2: capture &2 cannot be defined without &1
(elixir) src/elixir_fn.erl:118: :elixir_fn.do_capture/4
(elixir) expanding macro: Kernel.|>/2
iex:2: (file)
The result is somewhat expected. My question is how to bypass this, how can I use second element as argument without using the first one?
Upvotes: 1
Views: 854
Reputation: 222128
Like the error message says, you cannot use just the second argument using the capture operator, BUT, the function fn({_k, v}) -> is_binary(v) end
only takes one argument, which is a 2 element tuple, not 2 arguments. You can use elem/2
if you don't want to name it:
iex(1)> %{name: "Daniel", dob: 2016, email: "[email protected]"} |>
...(1)> Enum.filter(&is_binary(elem(&1, 1))) |>
...(1)> Enum.into(%{})
%{email: "[email protected]", name: "Daniel"}
For this particular use case, you can also use :maps.filter/2
. It's shorter than your original code and likely more efficient:
iex(2)> :maps.filter fn k, v -> is_binary(v) end, %{name: "Daniel", dob: 2016, email: "[email protected]"}
%{email: "[email protected]", name: "Daniel"}
Upvotes: 2