【问题标题】:Recursively convert Map to Keyword List递归地将 Map 转换为关键字列表
【发布时间】:2018-09-20 08:37:17
【问题描述】:

我在网上找到了一个把地图变成关键词列表的函数,但是它不是递归的:

def to_keyword_list(dict) do
    Enum.map(dict, fn({key, value}) -> {String.to_atom(key), value} end)
end

然后我做了这个,但它给了我一个错误。

def tokey(dict) do
  Enum.map(dict, fn({key, value}) ->
    if is_map value do
      {String.to_atom(key), tokey(value)}
    else
      {String.to_atom(key), value}
    end
  end)
end

第一个结果:

["calig├╝eva": %{speeking: "speeeeeeee"}, test: "teet", tututu: "tururuuu"]

第二个结果:

** (ArgumentError) argument error
    :erlang.binary_to_atom(:speeking, :utf8)
    code.exs:10: anonymous fn/1 in Util.tokey/1
    (elixir) lib/enum.ex:1233: anonymous fn/3 in Enum.map/2
    (stdlib) lists.erl:1263: :lists.foldl/3
    (elixir) lib/enum.ex:1772: Enum.map/2
    code.exs:8: anonymous fn/1 in Util.tokey/1
    (elixir) lib/enum.ex:1233: anonymous fn/3 in Enum.map/2
    (stdlib) lists.erl:1263: :lists.foldl/3

有没有更简单或更有效的方法来做到这一点?为什么它会显示该错误?我不能从自身内部调用函数吗?

第一个将ü 更改为u 的结果:

[caligueva: %{speeking: "speeeeeeee"}, test: "teet", tututu: "tururuuu"]

第二个输出同样的错误。这是我正在使用的地图:

map = %{
  "test" => "teet",
  "tututu" => "tururuuu",
  "caligueva" => %{"speeking": "speeeeeeee"}
}

【问题讨论】:

  • 你为什么要在这里创建原子?当您在其中有 ├╝ 时,原子不能包含代码点 > 255 的字符。
  • 我将使用一个需要关键字列表作为表单的模块(HTTPoison),所以我将使用 Poison.decode json-to-map 来接收,这个函数编码输出。另外,我尝试不使用特殊字符,它给出了完全相同的错误。
  • 对了,我看错了。错误是因为您在已经是原子 (:speeking) 的东西上调用了 String.to_atom。 (您稍后会遇到特殊字符错误。)
  • HTTPoison 是否支持嵌套关键字列表形式?似乎不适合我。

标签: dictionary recursion elixir


【解决方案1】:

用于在 Elixir 中递归地将 Maps 转换为 Keyword Lists

defmodule MyMap do
  def to_keyword_list(map) do
    Enum.map(map, fn {k,v} ->
      v = cond do
        is_map(v) -> to_keyword_list(v)
        true      -> v
      end

      {String.to_atom("#{k}"), v}           
    end)
  end
end

但正如@Dogbert 已经提到的,"Pure" Atoms cannot contain codepoints above 255,所以你的映射键应该是简单的字符串/原子:

iex(1)> MyMap.to_keyword_list(%{"caligueva" => %{speeking: "speeeeeeee"}, "test" => "teet", "tututu" => "tururuuu"})
[caligueva: [speeking: "speeeeeeee"], test: "teet", tututu: "tururuuu"]

【讨论】:

  • String.to_atom("#{k}") 是否使放置在其中的任何类型成为字符串然后成为原子?
  • 是的,只要广告支持字符串转字符协议
【解决方案2】:

这里是重构的转换代码:

def map_to_keyword_list(map), do: convert(map)

defp convert(map) when is_map(map), do: Enum.map(map, fn {k,v} ->{String.to_atom(k),convert(v)}  end) 
defp convert(v), do: v

【讨论】:

  • 这有什么好处?为什么要定义两次?
  • 您可以将转换函数用作私有函数。编辑答案,将 def 更改为 defp。
  • 此外,您能否进一步解释两次定义的内容。 @Besto
  • convert 被定义了两次。第一个在调用时执行,参数是一个映射,第二个在调用时执行,参数是其他任何东西。如果是映射,则映射映射到映射中每个键和值的{k, v}v 的值也会被转换,因此只要 v 是一个映射,调用 map_to_keyword_list 所产生的转换将返回一个嵌套的关键字列表值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-20
  • 2012-02-14
  • 2015-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-24
相关资源
最近更新 更多