web-dev-qa-db-ja.com

Elixirでマップキーを文字列から原子に変換する方法

Elixirで%{"foo" => "bar"}%{foo: "bar"}に変換する方法は何ですか?

62
NoDisplayName

内包表記 を使用します。

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"}
79

これを行う最も簡単な方法は、Map.newを使用することです。

%{"a" => 1, "b" => 2} 
|> Map.new(fn {k, v} -> {String.to_atom(k), v} end)      

=> %{a: 1, b: 2}
41
PlagueHammer

Enum.reduce/String.to_atom/1 の組み合わせを使用できます

%{"foo" => "bar"}
|> Enum.reduce(%{}, fn ({key, val}, acc) -> Map.put(acc, String.to_atom(key), val) end)

ただし、ユーザー入力に基づいたアトムへの変換には注意する必要があります。アトムはガベージコレクションされないため、メモリリークが発生する可能性があります。 この問題 を参照してください。

atomが既に存在する場合、これを防ぐために String.to_existing_atom/1 を使用できます。

22
Gazler

@emailleninの答えに基づいて、キーがすでにアトムであるかどうかを確認して、すでにアトムであるキーを取得するときにString.to_atomによって発生するArgumentErrorを回避できます。

for {key, val} <- string_key_map, into: %{} do
  cond do
    is_atom(key) -> {key, val}
    true -> {String.to_atom(key), val}
  end
end
7
momo

このためのライブラリがあります https://hex.pm/packages/morphix 。また、埋め込みキーの再帰関数も備えています。

ほとんどの作業はこの関数で行われます。

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

これは再帰的に呼び出されます。 @Galzerの回答を読んだ後、おそらくすぐにString.to_existing_atomを使用するように変換するでしょう。

6
philosodad

モジュール形式の@emailleninの回答のバージョンを次に示します。

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
4
Jason Axelson
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(%{})
1
Chris Almeida

ここでは、再帰的に(1)マップキーをスネークケースとしてフォーマットし、(2)それらをアトムに変換するために使用します。 neverはホワイトリストに登録されていないユーザーデータをガベージコレクションされないため、アトムに変換する必要があることに注意してください。

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
1
Betree
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
1
Zubair Nabi