How to convert map keys atoms to string?

I have a map like this

%{
  day: [:*],
  extended: false,
  hour: [:*],
  minute: [{:/, :*, 21}],
  month: [:*],
  reboot: false,
  second: [:*],
  weekday: [:*],
  year: [:*]
}

When I’m trying to convert this by this method

Enum.reduce(%{}, fn ({key, val}, acc) → Map.put(acc, String.to_atom(key), val) end)

It’s giving me this

** (ArgumentError) errors were found at the given arguments:

  * 1st argument: not a binary

    :erlang.binary_to_atom(:day, :utf8)
    (stdlib 3.15.2) erl_eval.erl:685: :erl_eval.do_apply/6
    (stdlib 3.15.2) erl_eval.erl:790: :erl_eval.eval_map_fields/5
    (stdlib 3.15.2) erl_eval.erl:251: :erl_eval.expr/5
    (stdlib 3.15.2) maps.erl:410: :maps.fold_1/3

I don’t know much about this error. Please guide me to some docs here

and how do I solve this problem efficiently ?

1 Like

You don’t need a reduce in that case because You transform a map, You do not reduce it…

map = %{
  day: [:*],
  extended: false,
  hour: [:*],
  minute: [{:/, :*, 21}],
  month: [:*],
  reboot: false,
  second: [:*],
  weekday: [:*],
  year: [:*]
}
Map.new map, fn {k, v} -> {to_string(k), v} end

And it’s to_string when You want to convert atoms to string.

8 Likes

As @kokolegorille said this is a perfect use for Map.new/2.

Just in case you want to fix your code with Enum.reduce/3,

  1. it’s fine to use reduce because under the scene, Map.new/2 is built on top of Enum.map/2 which uses Enum.reduce/3 (in this case of Map).

  2. you can change your code into something like this:

    map = %{foo: "bar"}
    
    Enum.reduce(map, %{}, fn {key, value}, acc ->
      Map.put(acc, to_string(key), value)
    end)
    

ps. You can use a comprehension too:

for {k, v} <- map, into: %{}, do: {to_string(k), v}
5 Likes