Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elixir: rename key in dictionary

I have following list of maps:

[
  %{
    code: "test",
    expired_at: ~U[2020-10-27 17:49:47Z],
  },
  %{
    code: "test",
    expired_at: ~U[2021-07-30 13:54:11Z],
  }
]

What is the most sophisticated way to rename key code to product_code for all map entities in the list?

like image 802
Rudziankoŭ Avatar asked Oct 19 '25 09:10

Rudziankoŭ


2 Answers

Probably not "the most sophisticated way", but I think a nice way would be with pattern matching, using an anonymous function with a clause to match what you want to change, and one for everything else:

iex> l = [
...>   %{
...>     code: "test",
...>     expired_at: ~U[2020-10-27 17:49:47Z],
...>   },
...>   %{
...>     code: "test",
...>     expired_at: ~U[2021-07-30 13:54:11Z],
...>   }
...> ]
[
  %{code: "test", expired_at: ~U[2020-10-27 17:49:47Z]},
  %{code: "test", expired_at: ~U[2021-07-30 13:54:11Z]}
]
iex> Enum.map(l, &Map.new(&1, fn
...>   {:code, code} -> {:product_code, code}
...>   pair -> pair
...> end))
[
  %{expired_at: ~U[2020-10-27 17:49:47Z], product_code: "test"},
  %{expired_at: ~U[2021-07-30 13:54:11Z], product_code: "test"}
]

Notice the use of Map.new/2 which creates a Map from the given enumerable with the elements that result from applying the given function to the enumerable

Or an alternative that might be more clear, without using Map.new/2 like that or iterating over the maps' keys, could be using Map.delete/2 and Map.put/3:

iex> Enum.map(l, fn %{code: code} = element ->
...>   element
...>   |> Map.delete(:code)
...>   |> Map.put(:product_code, code)
...> end)
[
  %{expired_at: ~U[2020-10-27 17:49:47Z], product_code: "test"},
  %{expired_at: ~U[2021-07-30 13:54:11Z], product_code: "test"}
]
like image 149
sbacarob Avatar answered Oct 21 '25 10:10

sbacarob


While the answer by @sbacarob is perfectly correct, it might quickly become noisy if the subject to update is deeply nested.

In such a case elixir provides a great, extremely underrated mechanism to update nested structures, called Access. For this particular case, we might use Kernel.update_in/3 with Access.all/0 to get to all the elements of the list.

update_in(
  list,
  [Access.all()],
  &(with {v, m} <- Map.pop(&1, :code),
    do: Map.put(m, :product_code, v))
)
#⇒ [
#    %{expired_at: ~U[2020-10-27 17:49:47Z], product_code: "test"},
#    %{expired_at: ~U[2021-07-30 13:54:11Z], product_code: "test"}
#  ]
like image 23
Aleksei Matiushkin Avatar answered Oct 21 '25 10:10

Aleksei Matiushkin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!