Reputation: 463
I just want to know if there's a clean way to get the "other" element from a map in Elixir. By "other" I mean a second key-value pair, whose key I don't know.
Example: %{success: boolean, other => value}
This is the best I could come up with:
case map do
%{success: true} ->
other = map |> Map.delete(:success) |> Map.values |> List.first
# Do something with other
%{success: false} ->
error = map |> Map.delete(:success) |> Map.values |> List.first
# Do something with error
end
Upvotes: 0
Views: 805
Reputation: 48599
iex(9)> map = %{:success => true, {1,2,3} => 10}
%{:success => true, {1, 2, 3} => 10}
iex(10)> List.first(for {key, val} <- map, key != :success, do: val)
10
Upvotes: 0
Reputation: 121000
I would go with old good Enum.reduce/3
:
Enum.reduce %{success: true, foo: 42}, %{state: nil, map: %{}}, fn
{:success, value}, acc -> %{acc | state: value}
{key, value}, acc -> %{acc | map: Map.put(acc.map, key, value)}
end
#⇒ %{map: %{foo: 42}, state: true}
Now you might do whatever is needed without code duplication. Actually, the tuple is fine for collecting the result:
{success, map} =
Enum.reduce %{success: true, foo: 42}, {nil, %{}}, fn
{:success, value}, {_, acc} -> {value, acc}
{key, value}, {state, acc} -> {state, Map.put(acc, key, value)}
end
#⇒ {true, %{foo: 42}}
Upvotes: 1
Reputation: 15045
There's Map.pop/3 function, which accepts map
and a key and returns a tuple with the value and a map without the key:
Map.pop %{ a: 1, b: 2 }, :a
# => {1, %{b: 2}}
and will refactor your code into something like:
case Map.pop(map, :success) do
{true, other_map} ->
other = other_map |> Map.values |> List.first
# Do something with other
{false, other_map} ->
error = other_map |> Map.values |> List.first
# Do something with error
end
Upvotes: 2