Consider the list of string values,
lines = ["foo: 1", "bar: 2", "baz: 3"]
That one might transform into the Elixir map,
%{ "foo": "1", "bar": "2", "baz": "3"}
using a simple Enum.reduce
,
Enum.reduce(lines, %{}, fn(line, result) ->
[key, value] = String.split(line, ": ")
Map.put(result, key, value)
end)
How might one refactor this into something more succinct, specifically with the third argument passed to reduce
? For example, my instinct wants to do something like,
Enum.reduce(lines, %{}, fn(line, result) ->
String.split(line, ": ") |> Map.put(result)
end)
but the Elixir pipe operator doesn't allow piping multiple values nor piping them to anything other than the first argument.
2 Answers 2
You can do this with an anonymous function
Enum.reduce(lines, %{}, fn(line, result) ->
String.split(line, ": ")
|> (fn(x) -> Map.put(result, hd(x), List.last(x)) end).()
end)
You can also do it like this
Enum.reduce(lines, [], fn(line, result) -> result ++ String.split(line, ": ") end)
|> Enum.chunk(2)
|> Map.new(fn [k, v] -> {k, v} end)
which I less efficient, because it does 2 iterations, but I think it looks cleaner.
This would also be solvable with a map instead of a reduce
lines
|> Enum.map(&String.split(&1, ": "))
|> Map.new(&List.to_tuple/1)