developer tip

Elixir에서 맵 키를 문자열에서 원자로 변환하는 방법

copycodes 2020. 11. 13. 23:41
반응형

Elixir에서 맵 키를 문자열에서 원자로 변환하는 방법


변환하는 방법은 무엇입니까 %{"foo" => "bar"}%{foo: "bar"}비약으로는?


이해력 사용 :

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

이 작업을 수행하는 가장 쉬운 방법은 다음을 사용하는 것입니다 Map.new.

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

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

Enum.reduce / 3String.to_atom / 1 의 조합을 사용할 수 있습니다.

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

그러나 사용자 입력을 기반으로 원자로 변환하는 것은 가비지 수집되지 않아 메모리 누수가 발생할 수 있으므로주의해야합니다. 이 문제를 참조하십시오 .

아톰이 이미 존재하는 경우이를 방지하기 위해 String.to_existing_atom / 1사용할 수 있습니다 .


@emaillenin의 답변을 기반으로 키가 이미 원자인지 확인하여 이미 원자 인 ArgumentError키를 가져올 때 String.to_atom에 의해 발생 하는 것을 피할 수 있습니다.

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

이를위한 라이브러리, 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사용하도록 변환 할 것입니다 .


다음은 모듈 형식의 @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

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

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) 맵 키를 snakecase로 포맷하고 (2) 원자로 변환하는 데 사용하는 것입니다. 화이트리스트에없는 사용자 데이터는 가비지 수집되지 않으므로 아톰으로 변환 해서는 안됩니다 .

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

참고URL : https://stackoverflow.com/questions/31990134/how-to-convert-map-keys-from-strings-to-atoms-in-elixir

반응형