Quel est le moyen de convertir %{"foo" => "bar"}
à %{foo: "bar"}
dans Elixir?
Utilisez Compréhensions :
iex(1)> string_key_map = %{"foo" => "bar", "hello" => "world"}
%{"foo" => "bar", "hello" => "world"}
iex(2)> for {key, val} <- string_key_map, into: %{}, do: {String.to_atom(key), val}
%{foo: "bar", hello: "world"}
Je pense que la meilleure façon de faire est d’utiliser Map.new
:
%{"a" => 1, "b" => 2}
|> Map.new(fn {k, v} -> {String.to_atom(k), v} end)
=> %{a: 1, b: 2}
Vous pouvez utiliser une combinaison de Enum.reduce/ et String.to_atom/1
%{"foo" => "bar"}
|> Enum.reduce(%{}, fn ({key, val}, acc) -> Map.put(acc, String.to_atom(key), val) end)
Cependant, vous devriez vous méfier de la conversion en atomes en fonction de la saisie de l'utilisateur, car ils ne seront pas mis au rebut, ce qui peut entraîner une fuite de mémoire. Voir ce numéro .
Vous pouvez utiliser String.to_existing_atom/1 pour éviter cela si atom existe déjà.
Pour vous appuyer sur la réponse de @ emaillenin, vous pouvez vérifier si les clés sont déjà des atomes, afin d'éviter le ArgumentError
qui est généré par String.to atom lorsqu'il obtient une clé qui est déjà un atome.
for {key, val} <- string_key_map, into: %{} do
cond do
is_atom(key) -> {key, val}
true -> {String.to_atom(key), val}
end
end
Il existe une bibliothèque pour cela, https://hex.pm/packages/morphix . Il a également une fonction récursive pour les clés intégrées.
La majeure partie du travail est effectuée dans cette fonction:
defp atomog (map) do
atomkeys = fn({k, v}, acc) ->
Map.put_new(acc, atomize_binary(k), v)
end
Enum.reduce(map, %{}, atomkeys)
end
defp atomize_binary(value) do
if is_binary(value), do: String.to_atom(value), else: value
end
Qui s'appelle récursivement. Après avoir lu la réponse de @ Galzer, je vais probablement convertir ceci en utilisant String.to_existing_atom
bientôt.
Voici une version de la réponse de @ emaillenin sous forme de module:
defmodule App.Utils do
# Implementation based on: http://stackoverflow.com/a/31990445/175830
def map_keys_to_atoms(map) do
for {key, val} <- map, into: %{}, do: {String.to_atom(key), val}
end
def map_keys_to_strings(map) do
for {key, val} <- map, into: %{}, do: {Atom.to_string(key), val}
end
end
m = %{"key" => "value", "another_key" => "another_value"}
k = Map.keys(m)|> Enum.map(&(String.to_atom(&1)))
v = Map.values(m)
result = Enum.Zip(k, v) |> Enum.into(%{})
Voici ce que j’utilise pour récursivement (1) formater les clés de carte en tant que snakecase et (2) les convertir en atomes. N'oubliez pas que vous devez jamais convertir les données utilisateur non inscrites sur la liste blanche en atomes, car elles ne sont pas récupérées.
defp snake_case_map(map) when is_map(map) do
Enum.reduce(map, %{}, fn {key, value}, result ->
Map.put(result, String.to_atom(Macro.underscore(key)), snake_case_map(value))
end)
end
defp snake_case_map(list) when is_list(list), do: Enum.map(list, &snake_case_map/1)
defp snake_case_map(value), do: value
defmodule Service.MiscScripts do
@doc """
Changes String Map to Map of Atoms e.g. %{"c"=> "d", "x" => %{"yy" => "zz"}} to
%{c: "d", x: %{yy: "zz"}}, i.e changes even the nested maps.
"""
def convert_to_atom_map(map), do: to_atom_map(map)
defp to_atom_map(map) when is_map(map), do: Map.new(map, fn {k,v} -> {String.to_atom(k),to_atom_map(v)} end)
defp to_atom_map(v), do: v
end