如何将地图键从string转换成Elixir中的primefaces
在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"}
您可以使用Enum.reduce / 3和String.to_atom / 1的组合
%{"foo" => "bar"} |> Enum.reduce(%{}, fn ({key, val}, acc) -> Map.put(acc, String.to_atom(key), val) end)
但是,你应该谨慎的基于用户input转换为primefaces,因为他们不会被垃圾收集,这可能导致内存泄漏。 看到这个问题 。
如果primefaces已经存在,可以使用String.to_existing_atom / 1来防止这种情况。
我认为最简单的方法是使用Map.new
:
h = %{"foo" => "bar"} Map.new(h, fn {k, v} -> {String.to_atom(k), v} end) => %{foo: "bar"}
要在@emaillenin的答案上构build,可以检查键是否已经是primefaces,以避免String.to_atom在获得已经是primefaces的键时引发的ArgumentError
。
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 。 它也有embedded式键的recursionfunction。
大部分的工作是在这个function完成的:
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
这被recursion地调用。 阅读@ 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 eg %{"c"=> "d", "x" => %{"yy" => "zz"}} to %{c: "d", x: %{yy: "zz"}}, ie 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(%{})