Раскрытие: автор lens
здесь.
Я не мог придумать, как просто сделать это с помощью встроенного Access
, но вы можете добиться этого с помощью lens
lib (https://hex.pm/packages/lens):
data = %{
"fname" => "",
"lname" => "",
"addresses" => %{
"0" => %{
"address" => ""
}
},
"phone_numbers" => %{
"0" => %{"number" => ""},
"1" => %{"number" => ""},
"2" => %{"number" => ""}
}
}
data
|> put_in(
[
Lens.both(
Lens.root(),
Lens.keys(["addresses", "phone_numbers"]) |> Lens.map_values()
)
|> Lens.key("account_id")
],
2
)
|> IO.inspect()
# =>
%{
"account_id" => 2,
"addresses" => %{"0" => %{"account_id" => 2, "address" => ""}},
"fname" => "",
"lname" => "",
"phone_numbers" => %{
"0" => %{"account_id" => 2, "number" => ""},
"1" => %{"account_id" => 2, "number" => ""},
"2" => %{"account_id" => 2, "number" => ""}
}
}
Lens.both(
Lens.root(),
Lens.keys(["addresses", "phone_numbers"]) |> Lens.map_values()
)
|> Lens.key("account_id")
- это бит ключа. По сути, он гласит: «принимать каждое значение под ключом account_id FROM ((все данные) AND (каждое значение карты в картах, расположенных под ключами address и phone_numbers))».
Редактировать:
ОП упоминает в комментарии, что ключи могут быть неизвестны заранее. Вы можете добиться того же эффекта, не указав их явно с помощью:
Lens.both(
Lens.root(),
Lens.map_values() |> Lens.filter(&is_map/1) |> Lens.map_values()
)
|> Lens.key("account_id")