gpt4 book ai didi

python - 如何将算法转化为函数式编程?

转载 作者:行者123 更新时间:2023-12-01 08:25:10 24 4
gpt4 key购买 nike

我对函数式编程和 Elixir 完全陌生,即使在学习了语法之后,我也很难集中精力解决不变性问题。

考虑一下我用 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

我知道代码在很多地方都非常低效,特别是在列表末尾 - 但我不确定如何以有效的方式重写它们,更重要的是,我完全被阻止了标记线。我认为我以命令式/面向对象的方式思考太多。对于理解函数式编程的帮助将不胜感激。

最佳答案

尝试使用递归而不是循环,从没有parent_id(或nil)的节点开始,并为每个子节点递归构建子树。

下面的代码很简单,但大部分是不言自明的。

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

%{ map | key1: val1, key2: val2} 是 Elixir 用于更新 map 的简写

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)

关于python - 如何将算法转化为函数式编程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54305308/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com