首页 > 解决方案 > 榆树 - 树 - 将分支添加到另一棵树 - 递归 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,但如果推荐的话,我可以使用另一个库。

标签: for-looprecursionfunctional-programmingtreeelm

解决方案


在您的代码中,在我看来您从未真正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


推荐阅读