Python 如何将算法转换为函数式编程?

Python 如何将算法转换为函数式编程?,python,elixir,Python,Elixir,我对函数式编程和长生不老药一无所知,即使在学习了语法之后,我也很难集中精力解决不变性问题 考虑我用python编写的以下简单算法。它接收树的级别列表。每个级别都是一个节点列表,其中节点包含一个id、一个(最初)空的子节点列表和指向其父节点的指针。它对树进行排序,使每个父级在其子级列表中都有其子级,并返回根。例如,以下输入: [[{"id": 10, "children": [], "parent_id": null}], [{"id": 12, "children":

我对函数式编程和长生不老药一无所知,即使在学习了语法之后,我也很难集中精力解决不变性问题

考虑我用python编写的以下简单算法。它接收树的级别列表。每个级别都是一个节点列表,其中节点包含一个id、一个(最初)空的子节点列表和指向其父节点的指针。它对树进行排序,使每个父级在其子级列表中都有其子级,并返回根。例如,以下输入:

[[{"id": 10,
    "children": [],
    "parent_id": null}],
  [{"id": 12,
    "children": [],
    "parent_id": 10},
   {"id": 18,
    "children": [],
    "parent_id": 10},
   {"id": 13,
    "children": [],
    "parent_id": 10}],
  [{"id": 17,
    "children": [],
    "parent_id": 12},
   {"id": 16,
    "children": [],
    "parent_id": 13},
   {"id": 15,
    "children": [],
    "parent_id": 12}]}]
将转换为以下输出:

[{"id": 10,
  "children":
   [{"id": 12,
     "children":
      [{"id": 17,
        "children": [],
        "parent_id": 12},
       {"id": 15,
        "children": [],
        "parent_id": 12}],
     "parent_id": 10},
    {"id": 18,
     "children": [],
     "parent_id": 10},
    {"id": 13,
     "children":
      [{"id": 16,
        "children": [],
        "parent_id": 13}],
     "parent_id": 10}],
  "parent_id": null}]
守则:

def build_tree(levels):
            ids_to_nodes = []
            for i in range(len(levels)):
                    level = levels[i]
                    ids_to_nodes.append({})
                    for node in level:
                            ids_to_nodes[i][node["id"]] = node

                    if i > 0:
                            for node in level:
                                    levels[i - 1][node["parent_id"]]["children"].append(node)

            return levels[0].values()
我在elixir中最接近实现这一点的是

def fix_level(levels, ids_to_nodes, i) do
      if i < length(levels) do
              level = Enum.at(levels, i)
              new_level =
              Enum.reduce level, %{},  fn node, acc ->
                Map.put(acc, node["id"], node)
              end
              ids_to_nodes = ids_to_nodes ++ [new_level]

              if i > 0 do
                Enum.reduce level, Enum.at(ids_to_nodes, i - 1)[node["parent_id"]], fn node, acc ->
                  Map.put(acc, "children", Enum.at(ids_to_nodes, i - 1)[node["parent_id"]]["children"] ++ [node]) # Doesn't work coz creates new map
                end
              end

              fix_level(params, ids_to_nodes, i + 1)
      end
      Map.values(ids_to_nodes[0])
    end


  def fix(levels) do
    fix_level(levels, ids_to_nodes, 0)
  end
def fix_level(levels,id_to_nodes,i)do
如果我<长度(级别)怎么办
级别=枚举(级别,i)
新水平=
Enum.reduce级别,%{},fn节点,acc->
映射放置(acc,节点[“id”],节点)
结束
ids_to_nodes=ids_to_nodes++[新_级别]
如果我大于0,我会这样做
Enum.reduce level,Enum.at(id_to_nodes,i-1)[node[“parent_id”]”,fn node,acc->
Map.put(acc,“children”,Enum.at(id_to_nodes,i-1)[node[“parent_id”]][“children”]+[node])不起作用,因为z创建了新的映射
结束
结束
修复级别(参数、ID到节点、i+1)
结束
值(ID_到_节点[0])
结束
def修复(级别)do
修复\u级别(级别、ID到\u节点、0)
结束

我知道代码在很多地方效率都很低,尤其是在列表的末尾——但我不知道如何高效地重写它们,更重要的是,我完全被标记行阻塞了。我觉得我用命令式/面向对象的方式思考太多了。理解函数式编程的帮助将不胜感激。

尝试使用递归而不是循环,从没有父id(或无)的节点开始,递归地为每个子节点构建子树

下面的代码过于简单,但基本上是不言自明的

它获取当前父节点的子节点(根节点为nil)并为其每个子节点构建子树

%{map | key1:val1,key2:val2}是更新地图的灵丹妙药

defmodule TestModule do
    def build_tree(levels, parent_id \\ nil) do
        levels
        |> Enum.filter(& &1.parent_id == parent_id) # get children of parent_id
        |> Enum.map(fn level ->
            %{level | children: build_tree(levels, level.id)} # recursively build subtrees of current level
        end)
        # we should now have child nodes of parent_id with their children populated
    end
end

# sample input
levels = [
    %{id: 1, parent_id: nil, children: []},
    %{id: 2, parent_id: 1, children: []},
    %{id: 3, parent_id: 2, children: []},
    %{id: 4, parent_id: 2, children: []},
    %{id: 5, parent_id: 4, children: []},
    %{id: 6, parent_id: 1, children: []},
    %{id: 7, parent_id: 6, children: []},
    %{id: 8, parent_id: 6, children: []},
    %{id: 9, parent_id: nil, children: []},
    %{id: 10, parent_id: 9, children: []},
]

TestModule.build_tree(levels)

请提供编辑中提供的示例性输入和所需输出。谢谢你能再详细解释一下为什么会这样做,以及是如何做到的吗?”“试试这个”相当隐晦,不一定会对OP有所帮助。@Máté添加了更多细节