在 Elixir 中将地图转换为关键字列表

cjm*_*671 4 elixir

我有一张表格的地图:

%{"browser_name" => "Chrome", "platform" => "linux"}
Run Code Online (Sandbox Code Playgroud)

我需要将其转换为关键字列表:

[browser_name: "Chrome", platform: "linux"]
Run Code Online (Sandbox Code Playgroud)

实现这一目标的最佳方法是什么?

Nit*_*ain 11

这不是行得通吗:

 def convert_to_klist(map) do
   Enum.map(map, fn({key, value}) -> {String.to_existing_atom(key), value} end)
 end
Run Code Online (Sandbox Code Playgroud)

  • 并且请不要在函数名称中使用 CamelCase (7认同)
  • 试试这个:`String.to_existing_atom/1` (3认同)
  • 当心 `String.to_atom/1` 容易受到原子 DoS 攻击。 (2认同)

小智 10

您可以使用该Keyword.new函数并传入转换函数作为第二个参数。

Keyword.new(%{"browser_name" => "Chrome", "platform" => "linux"}, fn {k,v} -> {String.to_existing_atom(k), v} end)
> [browser_name: "Chrome", platform: "linux"]
Run Code Online (Sandbox Code Playgroud)

虽然这基本上等同于 @NiteRain 接受的答案,但我认为它更明确一点,并向未来的代码读者展示了您的意图。

请参阅: https: //hexdocs.pm/elixir/Keyword.html#new/2


Ale*_*kin 7

为了将来的读者,我会把它放在这里。

虽然人们肯定可能会String.to_atom/1在这里和那里盲目地调用,但强烈建议不要使用这种方法,因为它容易受到原子 DoS 攻击的影响。

以下是 Erlang 文档的摘录:

原子不会被垃圾收集。一旦一个原子被创建,它就永远不会被删除。如果达到原子数的限制(默认为 1,048,576),模拟器将终止。

因此,在连续运行的系统中,将任意输入字符串转换为原子可能是危险的。如果只允许某些明确定义的原子作为输入,list_to_existing_atom/1则可用于防范拒绝服务攻击。(所有被允许的原子必须在更早的时候创建,例如,通过简单地在一个模块中使用它们并加载该模块。)

http://erlang.org/doc/efficiency_guide/commoncaveats.html#list_to_atom-1

也就是说,无论您是从外部不受信任的来源接收映射(例如,它是对您的 API 的调用中的参数或其他东西),您都不能使用,String.to_atom/1而应该使用String.to_existing_atom/1

否则,带有简单随机密钥生成器的入侵者会毫无问题地炸毁你的ErlangVM


小智 7

备查。您还可以使用Enum.into/3

%{"browser_name" => "Chrome", "platform" => "linux"}
|> Enum.into([], fn {k, v} -> {String.to_existing_atom(k), v} end)
Run Code Online (Sandbox Code Playgroud)

或者更短的版本:

%{"browser_name" => "Chrome", "platform" => "linux"}
|> Enum.into([], &{String.to_existing_atom(elem(&1,0)), elem(&1,1)})
Run Code Online (Sandbox Code Playgroud)