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

bitxx 回答:Elm-树-将分支添加到另一棵树-递归forloop

在您的代码中,对我来说,您似乎从未真正从A-1-1提取tree1的孩子,所以让我们开始:

subtreeToMove =
    Maybe.withDefault (leaf <| "Failed to find node " ++ nodeToMove) <| get nodeToMove tree1

get函数通过值在树中找到一个节点。由于可能不存在具有指定值的节点,因此它将返回Maybe,因此我们传递了默认值。

接下来,您将在tree2中找到目标节点,并将该节点及其子节点附加在一起。由于目标节点是叶子,因此在这里我将使用replaceChildrenAt

treeWithNewNode =
    tree2 |> replaceChildrenAt newParentNode [ subtreeToMove ]

All done!

之所以提及这一点,是因为您将期望的结果描述为在树之间移动一个节点:所有数据在Elm中都是不可变的–因此,移动之后,tree1tree2还是一样。因此,来自tree1的子树已被复制到tree2

的副本中 ,

我没有replaceChildrenAt的解决方案来保留现有子级。

module Main exposing (main)

import Canopy exposing (Node,append,children,get,leaf,node,value)
import Html exposing (Html,b,div,h1,h2,li,text,ul)



-- add a node (and its children) under a branch in another tree


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"
                [ node "B-1-1-2-1"
                    [ leaf "don't remove me"
                    ],leaf "B-1-1-2-2"
                ]
            ]
        ]


tree3 : Node String
tree3 =
    let
        nodeToMove =
            Maybe.withDefault (leaf <| "Failed to find node " ++ "A-1-1") <| get "A-1-1" tree1

        newParentNodeValue =
            "B-1-1-2-1"

        treeWithNewNode =
            tree2 |> addNodeAt nodeToMove newParentNodeValue
    in
    treeWithNewNode



-- 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)
        ]


addNodeAt : Node String -> String -> Node String -> Node String
addNodeAt node firstParentNodeValue toTree =
    --Canopy.toList ->
    -- [("A-1-1",Nothing),("A-1-1-1",Just "A-1-1"),("A-1-1-2",...]
    node
        |> Canopy.toList
        |> List.foldl
            -- acc is the updated toTree
            (\( nodeValue,parentValue ) acc ->
                append
                    (Maybe.withDefault firstParentNodeValue parentValue)
                    nodeValue
                    acc
            )
            -- initial value
            toTree



在此处可见:https://ellie-app.com/79sd7H8fCjNa1


@ o-o-balance的答案和这个问题:https://elmprogramming.com/list.html#folding-a-list对我有很大帮助。

本文链接:https://www.f2er.com/3148522.html

大家都在问