For loop Elm-tree-将分支添加到另一棵树-递归forloop

For loop Elm-tree-将分支添加到另一棵树-递归forloop,for-loop,recursion,functional-programming,tree,elm,For Loop,Recursion,Functional Programming,Tree,Elm,我想把榆树的树枝从一棵树移到另一棵树 例如: 树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 -

我想把榆树的树枝从一棵树移到另一棵树

例如:

树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)
        ]
我的审判在这里:


我在这里使用的是Canopy,但如果推荐的话,我可以使用另一个库。

在您的代码中,在我看来,您从未从
tree1
中提取
A-1-1
的子项,所以让我们从这一点开始:

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


之所以提到这一点,是因为您将所需的结果描述为在树之间移动节点:所有数据在Elm中都是不可变的–因此,在移动之后,
tree1
tree2
仍然是相同的。因此,将
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",Just "A-1-1"),...]
    node
        |> Canopy.toList
        |> List.foldl
            -- acc is the updated toTree
            (\( nodeValue, parentValue ) acc ->
                append
                    (Maybe.withDefault firstParentNodeValue parentValue)
                    nodeValue
                    acc
            )
            -- initial value
            toTree



模块主显示(主)
导入(节点、附加、子节点、获取、叶、节点、值)
导入Html(Html、b、div、h1、h2、li、文本、ul)
--在另一棵树的分支下添加节点(及其子节点)
tree1:节点字符串
树1=
节点“A-1”
[节点“A-1-1”
[叶“A-1-1-1”
,节点“A-1-1-2”
[叶“A-1-1-2-1”
,叶“A-1-1-2-2”
]
]
]
tree2:节点字符串
树2=
节点“B-1”
[节点“B-1-1”
[叶“B-1-1-1”
,节点“B-1-1-2”
[节点“B-1-1-2-1”
[leaf“不要带走我”
]
,叶“B-1-1-2-2”
]
]
]
tree3:节点字符串
树3=
让
nodeToMove=
Maybe.withDefault(叶Html消息
视图节点=
让
子节点=
子节点
在里面
li[]
[b[]文本(值节点)]
,ul[](List.map视图节点子节点)
]
添加节点吃:节点字符串->字符串->节点字符串->节点字符串
AddNodeEat节点firstParentNodeValue到树=
--Canopy.toList->
--[(“A-1-1”,没什么),(“A-1-1-1”,只是“A-1-1”),(“A-1-1-2”,只是“A-1-1”),…]
节点
|>托利斯特酒店
|>List.foldl
--acc是更新的toTree
(\(nodeValue,parentValue)acc->
追加
(可能是默认的firstParentNodeValue parentValue)
节点值
行政协调会
)
--初始值
托特里
此处可见:



@o-o-balance的回答和这个:对我帮助很大。

请在这里发布完整的代码,包括数据类型的定义和所有的functions@Bergi我已经完成了密码。“不做我想跳的事”这不是一个非常有用的问题描述。代码是做什么的?等效的python代码是什么样子的,以及Canopy中具体缺少了什么可以做同样的事情?给我们一些帮助来理解这个问题,那么我们就更有可能帮助您。@glennsl它就是这样做的:谢谢@O.O.Balance.This正在处理replacingChildren。你是对的,我没有提取子项-我只是使用了值。但我确实尝试了节点(使用
get
&
mapChildrenAt
append
)结果是完全不同的——它实际上将两棵树合并在一起:。我会再试一次,然后发布一个不同的问题。
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",Just "A-1-1"),...]
    node
        |> Canopy.toList
        |> List.foldl
            -- acc is the updated toTree
            (\( nodeValue, parentValue ) acc ->
                append
                    (Maybe.withDefault firstParentNodeValue parentValue)
                    nodeValue
                    acc
            )
            -- initial value
            toTree