for-loop - 榆树 - 树 - 将分支添加到另一棵树 - 递归 forloop
问题描述
我想在榆树中将树枝从一棵树移到另一棵树。
例如:
树1:
A-1
- A-1-1
- - A-1-1-1
- - A-1-1-2
- - - A-1-1-2-1
- - - A-1-1-2-2
树 2
B-1
- B-1-1
- - B-1-1-1
- - B-1-1-2
- - - B-1-1-2-1
- - - B-1-1-2-2
我想将 A-1-1 移到 B-1-1-2-1 下,这应该会给
B-1
- B-1-1
- - B-1-1-1
- - B-1-1-2
- - - B-1-1-2-1
- - - - A-1-1
- - - - - A-1-1-1
- - - - - A-1-1-2
- - - - - - A-1-1-2-1
- - - - - - A-1-1-2-2
- - - B-1-1-2-2
我是函数式编程的新手。我可以想象如何在 Python 中使用递归 forloop 来做到这一点,但我被 Elm 困住了。
我可以轻松移动一个节点,但看不到如何递归添加子节点:
module Main exposing (..)
import Canopy exposing (Node, append, children, leaf, mapChildren, node, value)
import Html exposing (Html, b, div, h1, h2, li, text, ul)
import List exposing (map)
tree1 : Node String
tree1 =
node "A-1"
[ node "A-1-1"
[ leaf "A-1-1-1"
, node "A-1-1-2"
[ leaf "A-1-1-2-1"
, leaf "A-1-1-2-2"
]
]
]
tree2 : Node String
tree2 =
node "B-1"
[ node "B-1-1"
[ leaf "B-1-1-1"
, node "B-1-1-2"
[ leaf "B-1-1-2-1"
, leaf "B-1-1-2-2"
]
]
]
tree3 : Node String
tree3 =
let
nodeToMove =
"A-1-1"
newParentNode =
"B-1-1-2-1"
-- append the node only but not its descendants
treeWithNewNode =
append newParentNode nodeToMove tree2
-- type mismatch
-- treeWithNewNodeAndNewNodeChildren =
-- nodeToMove |> mapChildren (\child -> append
-- does not do what I was hopping for
-- newTree =
-- mapChildrenAt
-- nodeToMove
-- (\child -> append newParentNode (value child) treeWithNewNode)
-- tree2
newParentNode child tree2)
in
treeWithNewNode
main =
div []
[ h1 [] [ text "Adding a branch to another tree" ]
, h2 [] [ text "Tree 1" ]
, viewNode tree1
, h2 [] [ text "Tree 2" ]
, viewNode tree2
, h2 [] [ text "Move A-1-1 under B-1-1-2-1" ]
, viewNode tree3
]
viewNode : Node String -> Html msg
viewNode node =
let
subNodes =
children node
in
li []
[ b [] [ text (value node) ]
, ul [] (List.map viewNode subNodes)
]
我的试用版在这里: https ://ellie-app.com/7842F8jCLpCa1
我在这里使用 Canopy,但如果推荐的话,我可以使用另一个库。
解决方案
在您的代码中,在我看来您从未真正A-1-1
从 中提取 的孩子tree1
,所以让我们开始吧:
subtreeToMove =
Maybe.withDefault (leaf <| "Failed to find node " ++ nodeToMove) <| get nodeToMove tree1
get函数通过值在树中查找节点。由于可能没有具有指定值的节点,因此它返回 a Maybe
,因此我们传入一个默认值。
接下来,您在 中找到目标节点tree2
,并附加该节点及其子节点。我将在这里使用replaceChildrenAt,因为目标节点是叶子:
treeWithNewNode =
tree2 |> replaceChildrenAt newParentNode [ subtreeToMove ]
之所以提到这一点,是因为您将所需结果描述为在树之间移动节点:所有数据在 Elm 中都是不可变的——因此,在移动之后,tree1
它们tree2
仍然是相同的。所以相反,一个子树tree1
已经被复制到tree2
推荐阅读
- typescript - TS2339:“对象”类型上不存在属性“名称”
- python - 尝试逐步迭代python中的2个文件
- c - 为什么我可以修改这个 const char* 数组?
- java - 使用 PhotoView 放大后无法达到图像的原始大小
- java - 复制屏幕以在眼镜中使用。安卓
- java - OpenFeign 自定义错误解码器未捕获 ConnectionException
- python - 对 IO 绑定但独立的进程使用多处理或异步?
- laravel-mix - 如何在 Laravel Mix 上对 SASS/SCSS 进行 lint
- c++ - 在 ffmpeg 编码过程中更新参数正在运行
- node.js - 配置 Cypress 的 Electron 浏览器来处理下载