递归地将Map转换为关键字列表

时间:2017-03-19 05:33:23

标签: dictionary recursion elixir

我找到了一个在互联网上将地图转换为关键字列表的功能,但它不是递归的:

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

有更简单或更有效的方法吗?为什么它会显示错误?我不能从内部调用函数吗?

第一次更改ü的{​​{1}}的结果:

u

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

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

2 个答案:

答案 0 :(得分:2)

用于在Elixir中递归转换MapsKeyword 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"]

答案 1 :(得分: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