1
\$\begingroup\$

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.

\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

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.

\$\endgroup\$
2
\$\begingroup\$

This would also be solvable with a map instead of a reduce

lines
|> Enum.map(&String.split(&1, ": "))
|> Map.new(&List.to_tuple/1)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.