Let’s say we have:
game = %App.Games.Game{
id: "owieruoiewurwer",
players: %{
"jwuiyeywi_oiwueroiu" => %App.Games.Player{
admin: true,
card: "4"
},
"oiwueroiquw_ncjaioq" => %App.Games.Player{
admin: false,
card: "6"
}
}
}
What it the best way to put nil
in each player card ?
I used update_in/3
with Access.all/0
but can’t make it work with key-value pairs in :players
.
The only solution I found it is to convert my string keys into atoms, but that would force me to iterate through the player “list” two times.
You need to replace values to build the result.
- At the top level, we’re placing
players
- And then we need to iterate the map (as key-value pair), and for each value we need to put
nil
to card
key.
Quick solution:
v = %{
id: "owieruoiewurwer",
players: %{
"jwuiyeywi_oiwueroiu" => %{
admin: true,
card: "4"
},
"oiwueroiquw_ncjaioq" => %{
admin: false,
card: "6"
}
}
}
%{
v
| players:
Map.new(
v.players,
fn {k, player} -> {k, %{player | card: nil}} end
)
}
|> IO.inspect()
Note that it would be better to make functions to capture “domain logic” properly. e.g. if reset_game/1
or empty_card/1
.
1 Like
That worked just fine, thanks !
I’ve never used Map.new
before. Just to be sure, update_in/3
can’t be used in those circumstances ?
Since update_in needs keys to look at for a value, you cannot use it to transform all values.
If you need to change a value under a known path, you can use that for example.
1 Like
It can be used, but you need to write your own lens (Access.access_fun/2
type):
all_map_values = fn
:get, data, next ->
for {_, v} <- data, do: next.(v)
:get_and_update, data, next ->
{gets, updates} =
Enum.reduce(data, {[], []}, fn {k, v}, {gets, updates} ->
case next.(v) do
{get, update} -> {[get | gets], [{k, update} | updates]}
:pop -> {gets, updates}
end
end)
{:lists.reverse(gets), Map.new(updates)}
end
game = %{
id: "owieruoiewurwer",
players: %{
"jwuiyeywi_oiwueroiu" => %{
admin: true,
card: "4"
},
"oiwueroiquw_ncjaioq" => %{
admin: false,
card: "6"
}
}
}
IO.inspect(put_in(game, [:players, all_map_values, :card], nil))
4 Likes
I thought the Access
module could help me bypass that kind of function definition. But it makes a lot of sense to simply explain how to access the value like this in the end.
Thanks !