Elixir 展平/合并嵌套贴图

Elixir 展平/合并嵌套贴图,elixir,Elixir,假设我们有类似于地图的: %{"a": %{"b": 2, "c":5}, "d": 1} 在elixr中是否有类似于(js对同一问题的回答)的东西 最终结果应该是: %{"a.b": 4, "a.c":5, "d": 1} 我不知道内置函数,但当然有一些方法可以执行该转换: defmodule MyMaps do def flatten(map) when is_map(map) do map |> to_list_of_tuples |> Enum

假设我们有类似于地图的:

%{"a": %{"b": 2, "c":5}, "d": 1}
在elixr中是否有类似于(js对同一问题的回答)的东西

最终结果应该是:

%{"a.b": 4, "a.c":5, "d": 1}

我不知道内置函数,但当然有一些方法可以执行该转换:

defmodule MyMaps do
  def flatten(map) when is_map(map) do
    map
    |> to_list_of_tuples
    |> Enum.into(%{})
  end

  defp to_list_of_tuples(m) do
    m
    |> Enum.map(&process/1)
    |> List.flatten
  end

  defp process({key, sub_map}) when is_map(sub_map) do
    for { sub_key, value } <- sub_map do
      { join(key, sub_key), value }
    end
  end

  defp process({key, value}) do
    { key, value }
  end

  defp join(a, b) do
    to_string(a) <> "." <> to_string(b)
  end
end


m = %{ "a" => %{ "b" => 2, "c" => 5 }, "d" => 1 }

MyMaps.flatten m
# %{"a.b" => 2, "a.c" => 5, "d" => 1}

m1 = %{ a: %{ b: 2, c: 5}, d: 1}
MyMaps.flatten m1
# %{:d => 1, "a.b" => 2, "a.c" => 5}
defmodule MyMaps do
def展平(贴图)何时进行
地图
|>到\u列表\u元组的\u
|>Enum.into(%{})
结束
defp to_list_of_tuples(m)do
M
|>枚举映射(&process/1)
|>列表。展平
结束
defp进程({key,sub_-map})何时是_-map(sub_-map)do
对于{sub_key,值}%{“b”=>2,“c”=>5},“d”=>1}
MyMaps.flattem
#%{“a.b”=>2,“a.c”=>5,“d”=>1}
m1=%%{a:%%{b:2,c:5},d:1}
MyMaps.flattem1
#%{:d=>1,“a.b”=>2,“a.c”=>5}

由于我已经多次完成了这项任务,并且我自己也需要它,因此我已经为此创建了hex包
iteraptor

将其添加到mix.exs中的依赖项列表中:

def deps do
  [{:iteraptor, "~> 0.1.0"}]
end
然后像这样使用它:

iex(1)> %{a: %{b: 2, c: 5}, d: 1} |> Iteraptor.to_flatmap
%{"a.b": 2, "a.c": 5, d: 1}
它支持无限嵌套和
map
s和
list
s

守则的有关部分如下:

defmodule Iteraptor do
  @joiner "."

  @doc """
    iex> [:a, 42] |> Iteraptor.to_flatmap
    %{"0": :a, "1": 42}

    iex> %{a: 42} |> Iteraptor.to_flatmap
    %{a: 42}

    iex> %{a: 42, b: 42} |> Iteraptor.to_flatmap
    %{a: 42, b: 42}

    iex> %{a: %{b: 42}, d: 42} |> Iteraptor.to_flatmap
    %{"a.b": 42, d: 42}

    iex> %{a: [:b, 42], d: 42} |> Iteraptor.to_flatmap
    %{"a.0": :b, "a.1": 42, d: 42}

    iex> %{a: %{b: [:c, 42]}, d: 42} |> Iteraptor.to_flatmap
    %{"a.b.0": :c, "a.b.1": 42, d: 42}

    iex> %{a: %{b: 42}} |> Iteraptor.to_flatmap
    %{"a.b": 42}

    iex> %{a: %{b: %{c: 42}}} |> Iteraptor.to_flatmap
    %{"a.b.c": 42}

    iex> %{a: %{b: %{c: 42}}, d: 42} |> Iteraptor.to_flatmap
    %{"a.b.c": 42, d: 42}

    iex> %{a: %{b: %{c: 42, d: [nil, 42]}, e: [:f, 42]}} |> Iteraptor.to_flatmap
    %{"a.b.c": 42, "a.b.d.0": nil, "a.b.d.1": 42, "a.e.0": :f, "a.e.1": 42}
  """

  def to_flatmap(input, joiner \\ @joiner) when is_map(input) or is_list(input) do
    process(input, joiner)
  end

  @doc """
    iex> %{a: %{b: %{c: 42}}} |> Iteraptor.each(fn {k, v} -> IO.inspect({k, v}) end)
    %{"a.b.c": 42}
  """
  def each(input, joiner \\ @joiner, fun) do
    unless is_function(fun, 1), do: raise "Function or arity fun/1 is required"
    process(input, joiner, "", %{}, fun)
  end

  ##############################################################################

  defp process(input, joiner, prefix \\ "", acc \\ %{}, fun \\ nil)

  ##############################################################################

  defp process(input, joiner, prefix, acc, fun) when is_map(input) do
    input |> Enum.reduce(acc, fn({k, v}, memo) ->
      prefix = join(prefix, k, joiner)
      if is_map(v) or is_list(v) do
        process(v, joiner, prefix, memo, fun)
      else
        unless is_nil(fun), do: fun.({prefix, v})
        Map.put memo, prefix, v
      end
    end)
  end

  defp process(input, joiner, prefix, acc, fun) when is_list(input) do
    input
      |> Enum.with_index
      |> Enum.map(fn({k, v}) -> {v, k} end)
      |> Enum.into(%{})
      |> process(joiner, prefix, acc, fun)
  end

  ##############################################################################

  defp join(l, "", _) do
    String.to_atom(to_string(l))
  end

  defp join("", r, _) do
    String.to_atom(to_string(r))
  end

  defp join(l, r, joiner) do
    String.to_atom(to_string(l) <> joiner <> to_string(r))
  end
end
DefiteRaptor do模块
@“细木工”
@“医生”
iex>[:a,42]|>Iteraptor.to_平面图
%{“0”::a,“1”:42}
iex>%{a:42}|>Iteraptor.to_平面图
%{a:42}
iex>%{a:42,b:42}|>Iteraptor.to_平面图
%{a:42,b:42}
iex>%{a:%{b:42},d:42}|>Iteraptor.to_平面图
%{“a.b”:42,d:42}
iex>%{a:[:b,42],d:42}|>Iteraptor.to_平面图
%{“a.0”::b,“a.1”:42,d:42}
iex>%{a:%{b:[:c,42]},d:42}}
%{“a.b.0”::c,“a.b.1”:42,d:42}
iex>%{a:%{b:42}}|>Iteraptor.to_平面图
%{“a.b”:42}
iex>%{a:%{b:%{c:42}}}}}}
%{“a.b.c”:42}
iex>%{a:%{b:%{c:42}},d:42}|>Iteraptor.to_平面图
%{“a.b.c”:42,d:42}
iex>%{a:%{b:%{c:42,d:[nil,42]},e:[:f,42]}}}|>Iteraptor.to_平面图
%{“a.b.c”:42,“a.b.d.0”:无,“a.b.d.1”:42,“a.e.0”::f,“a.e.1”:42}
"""
def to_flatmap(input,joiner\\@joiner)何时是_map(input)或是_list(input)do
过程(输入、连接)
结束
@“医生”
iex>%{a:%{b:%{c:42}}}|>Iteraptor.each(fn{k,v}->IO.inspect({k,v})end)
%{“a.b.c”:42}
"""
定义每个(输入、加入者\\@joiner、乐趣)要做的事情
除非是功能(乐趣,1),否则执行:提高“功能或算术乐趣/1是必需的”
进程(输入,加入者,“,%{},乐趣)
结束
##############################################################################
defp进程(输入,连接符,前缀\\“”,acc\\%{},fun\\nil)
##############################################################################
defp过程(输入、连接、前缀、acc、fun)何时是映射(输入)do
输入|>Enum.reduce(acc,fn({k,v},memo)->
prefix=join(前缀,k,joiner)
如果是映射(v)或列表(v)do
流程(v、加入者、前缀、备忘录、乐趣)
其他的
除非是nil(fun),否则do:fun.({前缀,v})
地图。放备忘录,前缀,v
结束
(完)
结束
defp过程(输入、连接、前缀、acc、fun)何时是_列表(输入)do
输入
|>使用_索引枚举
|>map(fn({k,v})->{v,k}end)
|>Enum.into(%{})
|>流程(joiner、prefix、acc、fun)
结束
##############################################################################
defp join(l,“,uu)do
字符串。到_原子(到_字符串(l))
结束
defpjoin(“”,r,uu)do
字符串。到_原子(到_字符串(r))
结束
defp join(左、右、细木工)do
String.to_atom(to_String(l)joiner to_String(r))
结束
结束

从1.3版开始,Elixir中没有您描述的内置平坦/去平坦

然而,这是你们在问题中提到的翻译

flatte=fn
(数据)何时是列表(数据)或地图(数据)->
递归=fn
当列表(cur)和长度(cur)==0->
Map.put(结果,道具,[])
(递归、cur、prop、result)何时为列表(cur)->
Enum.reduce(Enum.with_index(cur),result,fn({value,index},acc)->
递归。(递归,值,>,acc)
(完)
(递归、cur、prop、result)当is_map(cur)和map_size(cur)==0->
put(结果,属性,%{})
(递归、cur、prop、result)何时为映射(cur)->
Enum.reduce(cur,result,fn({key,value},acc)->
递归。(如果字节大小(prop)==0,则递归,值)
钥匙
其他的
>
完(附件)
(完)
(递归、cur、prop、result)->
地图放置(结果、道具、当前)
结束
结果=递归。(递归,数据,%{})
结果
(数据)->
数据
结束
不平坦=fn
(数据)什么时候是地图(数据)->
正则表达式=~r/\.?([^.\[\]]+)\[(\d+)\]/
数组_get=fn
(数组、索引、默认值)当长度(数组)为默认值时
(数组,索引,_默认)->:lists.nth(索引+1,数组)
结束
数组\u new=fn(大小,数组),当为\u整数(大小)且大小>=0->
填充=fn
(\u0,数组)->数组
(fill,n,数组)->fill(fill,n-1,[nil |数组])
结束
填充。(填充、大小、数组)
结束
当是整数(索引)且索引>=0->
大小写长度(数组)do
当索引==0->[值]时为0
0->数组\u新建。(索引,[值])
^索引->数组+++[值]
长度>索引->列表时的长度。替换(数组、索引、值)
长度->数组++数组\新建。(索引-长度,[值])
结束
结束
reduce(data,nil,fn({prop,value},cur)->
递归=fn
(递归,[[uu,key]| rest],cur)->
cur=cur | |%{}
Map.put(cur,key,recurse.(recurse,rest,Map.get(cur,key,nil)))
(递归,[[uu,[uu,索引]| rest],cur)->
索引=字符串。到整数(索引)
cur=cur | |[]
数组放入。(cur,索引,递归。(递归,rest,数组获取。(cur,索引,nil)))
(_, [], _) ->
价值
结束
recurse.(recurse,Regex.scan(Regex,prop),cur)
defmodule MyMaps do
  def flatten(map) when is_map(map) do
    map
    |> to_list_of_tuples
    |> Enum.into(%{})
  end

  defp to_list_of_tuples(m) do
    m
    |> Enum.map(&process/1)
    |> List.flatten()
  end

  defp process({key, %DateTime{} = datetime}), do: {"#{key}", datetime}
  defp process({key, %Date{} = date}), do: {"#{key}", date}

  defp process({key, sub_map}) when is_map(sub_map) do
    for {sub_key, value} <- flatten(sub_map) do
      {"#{key}.#{sub_key}", value}
    end
  end

  defp process(next), do: next
end