Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Functional programming 在Elixir中展平嵌套贴图列表_Functional Programming_Elixir - Fatal编程技术网

Functional programming 在Elixir中展平嵌套贴图列表

Functional programming 在Elixir中展平嵌套贴图列表,functional-programming,elixir,Functional Programming,Elixir,我正在尝试展平嵌套贴图的列表,以便输出可以插入到数据库表中的贴图列表。嵌套映射可以包含映射列表。通常,嵌套映射的最小示例如下所示: %{ a: "a", b: "b", c: [ %{ d: "d1", e: [%{f: "f1", g: "g1"}], h: "h1", i

我正在尝试展平嵌套贴图的列表,以便输出可以插入到数据库表中的贴图列表。嵌套映射可以包含映射列表。通常,嵌套映射的最小示例如下所示:

  %{
    a: "a",
    b: "b",
    c: [
      %{
        d: "d1",
        e: [%{f: "f1", g: "g1"}],
        h: "h1",
        i: "i1"
      },
      %{
        d: "d2",
        e: [%{f: "f2", g: "g2"}],
        h: "h2",
        i: "i2"
      }
    ]
  }

我想要的结果是:


  [
    %{f: "f1", g: "g1", d: "d1", h: "h1", i: "i1", b: "b", a: "a"},
    %{f: "f2", g: "g2", d: "d2", h: "h2", i: "i2", b: "b", a: "a"}
  ]
  

列表的长度等于“终端”映射的数量(即本例中的
f
键)。您还将注意到,在嵌套发生的地方,
c
e
,这些键不是必需的,因此会被丢弃

我曾尝试在映射键上递归,但遇到的问题是,输出的长度始终是父映射中键数的长度

任何关于如何解决这个问题的帮助或想法都将不胜感激


谢谢

因为当我们遇到一个列表作为一个值时,我们确实需要遍历该级别,所以我们最好的朋友是。一旦我们惰性地执行它,所有内部操作也都是惰性的,直到我们需要终止结果以从
flatten/1
(使用
Enum.to_list/1
)返回它为止

defmodule-Flat-do
@等级库展平(map()):[map()]
def展平(输入),
do:input |>do_flant([%{}])|>Enum.to_list()
@doc“在这里,我们并行分叉并收集结果”
defp do_展平([%{}| ]=输入,acc)do
输入
|>Task.async_流(&do_扁平化(&1,acc))
|>流平面图(&elem(&1,1))
结束
@“医生”
将`{key,value}`对添加到每个列表中
在当前累积的结果中
"""
defp do_展平(%{}=input,acc)do
河流平面图(acc,fn列表->
Enum.reduce(输入、[list]、&do_展平(&1、&2))
(完)
结束
@doc“可枚举为值→去做吧”
当is_列表(v)或is_映射(v)时,defp do_展平({u k,v},acc),
do:do_展平(v,acc)
@doc“叶,添加到累加器中的所有列表”
defp do_展平({k,v},acc),
do:Stream.map(acc和map.put(&1,k,v))
结束
input=%{
a:“a”,b:“b”,
c:[
%{d:“d1”,e:[%{f:“f1”,g:“g1”}],h:“h1”,i:“i1”},
%{d:“d2”,e:[%{f:“f2”,g:“g2”}],h:“h2”,i:“i2”}]
}
放平
#⇒ [
#%{a:“a”,b:“b”,d:“d1”,f:“f1”,g:“g1”,h:“h1”,i:“i1”},
#%{a:“a”,b:“b”,d:“d2”,f:“f2”,g:“g2”,h:“h2”,i:“i2”}
#  ]

下面是一篇博客文章,详细介绍了这项技术。

如果嵌套映射与上面级别的映射具有相同的键,会发生什么?地图不能有重复的键。所有键都是唯一的,所以我不必对此进行解释。
'a'
是一个列表,
c
键的值是一个列表;为什么你希望后者扩大而第一个不扩大?我想我被《长生不老药》中的单引号和双引号绊倒了
'a'
实际上是一个字符串而不是一个字符表,而
c
是一个列表。所以我只是在扩展列表。我编辑了这个问题来澄清这一点。这是一篇非常及时的博客文章。谢谢你的解决方案,我还在处理细节。我一直认为延迟加载可以解决性能和内存问题。任何关于如何处理这样的问题以及如何在解决问题时进行调试的建议。延迟处理基本上是关于如何处理枚举的。贪婪操作(来自
Enum
模块)将操作应用于可枚举项中的所有元素,并返回中间结果。惰性(
Stream
)通过链中的所有操作传递每个元素。这里它更可取,因为枚举可在操作之间展开。我们从一个长度为1的列表开始,最后是一个任意长度的列表。建议很难:)在我意识到我要走的路之前,我绝对不会开始写代码。我曾尝试使用
访问权限进行此操作。all/0
,然后意识到它不适合,并切换到惰性任务。在任何步骤中,我都会使用
IO.inspect/0
(在我想要检查流之前终止流)。我很感激。在我看来,这里的关键洞见是,在分叉列表时,需要一个惰性函数调用。这样,您就可以将相同的累加器传递到分叉处的每个分支。仅供参考,我在一个有约7000个终端节点的映射列表上运行了这段代码,它可以工作,具有任意数量的分支。我正在验证数据!