Elm:如果结构是动态的(具有不同的深度),如何在Dict内部更新Dict?
给定以下文件系统结构:Elm:如果结构是动态的(具有不同的深度),如何在Dict内部更新Dict?,elm,Elm,给定以下文件系统结构: type alias FolderName = String type Folder = Folder { folderName : String , childFolders : Dict FolderName Folder } type alias FileSystem = Dict FolderName Folder fileSystem : FildeSystem fileSystem =
type alias FolderName = String
type Folder
= Folder
{ folderName : String
, childFolders : Dict FolderName Folder
}
type alias FileSystem =
Dict FolderName Folder
fileSystem : FildeSystem
fileSystem =
Dict.formList
[ ( "parent1"
, Folder
{ folderName = "parent1"
, childFolders =
Dict.fromList
[ ( "child1", Folder { folderName = "child1", childFolders = Dict.empty } )
, ( "child2", Folder { folderName = "child2", childFolders = Dict.empty } )
, ( "child3"
, Folder
{ folderName = "child3"
, childFolders =
Dict.formList
[ ( "sub-child_of_child3", Folder { folderName = "sub-child_of_child3", childFolders = Dict.empty } )
]
}
)
]
}
)
]
我希望能够通过调用函数并传入要创建新文件夹的位置动态创建新文件夹。。文件夹的名称以及文件系统Dict。大概是这样的:
createFolder: String -> FileSystem -> FolderName -> FileSystem
createFolder "parent1/child3/sub-child_of_child3" fileSystem "DynamicallyCreated"
因为无法预先知道文件系统Dict
是什么样子,而且因为这是elm(no for loops
)-我认为唯一的方法是使用递归
代码:
createFolder location fileSystem newFolderName=
let
locationAsArray = String.split "/" location
in
// first find the dict value. (that is the value of 'sub-child_of_child3' key, inside 'child3' Dict.)
findDictValueBasedOnLocation locationAsArray fileSystem
// then update the 'sub-child_of_child3' by inserting the newFolder.
|> (\ x -> { x | childFolders = Dict.insert newFolderName Folder { folderName = newFolderName, childFolders = Dict.empty } x.childFolders
// but how to reconsturct the child3, partent1 and finally the fileSystem now? Because this function it's supose to return a new fileSystem that contains the newly created folder.
findDictValueBasedOnLocation listDictKeys currentDict =
let
currentKey =
List.head listDictKeys
remainingKeys =
List.tail listDictKeys
in
-- when there is only one element in the listDictKeys that is: ["sub-child_of_child3"]- the recursive call stops/
if List.length listDictKeys == 1 then
Dict.get currentKey currentDict
|> Maybe.withDefault -- what to add here?
else
let
nextDict =
Dict.get currentKey currentDict
|> Maybe.withDefault --what to add here ?- don't know the type ..
in
-- recursive call with the remaining listDictKeys and nextDict which is in fact the current Dict value.
findDictValueBasedOnContext remainingKeys nextDict
使用递归查找相应的dict:
createFolder location fileSystem newFolderName=
let
locationAsArray = String.split "/" location
in
// first find the dict value. (that is the value of 'sub-child_of_child3' key, inside 'child3' Dict.)
findDictValueBasedOnLocation locationAsArray fileSystem
// then update the 'sub-child_of_child3' by inserting the newFolder.
|> (\ x -> { x | childFolders = Dict.insert newFolderName Folder { folderName = newFolderName, childFolders = Dict.empty } x.childFolders
// but how to reconsturct the child3, partent1 and finally the fileSystem now? Because this function it's supose to return a new fileSystem that contains the newly created folder.
findDictValueBasedOnLocation listDictKeys currentDict =
let
currentKey =
List.head listDictKeys
remainingKeys =
List.tail listDictKeys
in
-- when there is only one element in the listDictKeys that is: ["sub-child_of_child3"]- the recursive call stops/
if List.length listDictKeys == 1 then
Dict.get currentKey currentDict
|> Maybe.withDefault -- what to add here?
else
let
nextDict =
Dict.get currentKey currentDict
|> Maybe.withDefault --what to add here ?- don't know the type ..
in
-- recursive call with the remaining listDictKeys and nextDict which is in fact the current Dict value.
findDictValueBasedOnContext remainingKeys nextDict
您可以在这里看到两大问题:
parent1
)上更新现有内容?例:-请记住,此更新可能会发生在20级。。我如何告诉3级2,1关于此更新record.“someString”
来访问它的值,就像在javascript中一样。所以没有记录。格言似乎更有前途。。希望有人知道如何解决这个问题。谢谢:)这是一个很好的挑战!
首先,您要处理递归类型()。一个文件夹
包含一个Dict FolderName文件夹
,因此您确实需要在这里进行一些强输入
您希望在Dict
中的Dict
上执行递归更新
在下面,您可以找到一个示例解决方案代码,您可以将其复制/粘贴到其中
代码本身解释了不同函数的内部工作原理
一些评论:
- 对于更新
,一种常见模式是为整个Dict
(对于Dict
上的文档)提供键+更新功能。这比以下三步方法更有效:1)检索要更新的记录,2)更改记录,3)将其放回Dict.update
Dict
- 如果所提供路径中的任何节点出现故障,则该函数将只返回一个未更改的
文件系统
- 如果
已存在,则将替换具有该名称的整个现有文件夹(包括所有子文件夹)newFolderName
import Html exposing (text)
import Dict exposing (Dict)
---- TYPES
type alias FolderName = String
type Folder
= Folder
{ folderName : FolderName
, childFolders : FileSystem
}
type alias FileSystem =
Dict FolderName Folder
{- MAIN FUNCTION:
takes the first element in the path
and tries to do a recursive update on the children of the fileSystem
-}
insertFolder: String -> FolderName -> FileSystem -> FileSystem
insertFolder path newFolderName fileSystem =
let
nodeList = String.split "/" path
in
case nodeList of
node :: rest ->
-- if we have nodes, do recursive update on folders
fileSystem
|> Dict.update node (Maybe.map <| updateNestedFolder newFolderName rest)
[] ->
-- no path, so the new folder must be a root folder
fileSystem
|> Dict.inset newFolderName (newFolder newFolderName)
{- Recursive update function where the magic happens
-}
updateNestedFolder : FolderName -> List FolderName -> Folder -> Folder
updateNestedFolder newFolderName nodeList (Folder { folderName, childFolders }) =
case nodeList of
nextLevel :: rest ->
-- as long as there is a nodelist, we try to find deeper level
let
-- do recursive update on the children
newChildFolders =
childFolders
|> Dict.update nextLevel (Maybe.map <| updateNestedFolder newFolderName rest)
in
-- return the updated folder
Folder
{ folderName = folderName
, childFolders = newChildFolders
}
[] ->
-- this is the lowest level, so we need to add to this FileSystem
let
-- add newFolderName to the child folders
newChildFolders =
childFolders
|> Dict.insert newFolderName (newFolder newFolderName)
in
-- return the folder
Folder
{ folderName = folderName
, childFolders = newChildFolders
}
---- HELPERS
{- Create a new folder, without any children -}
newFolder : String -> Folder
newFolder folderName =
Folder
{ folderName = folderName
, childFolders = Dict.empty
}
------ EXAMPLE
fileSystem =
Dict.fromList
[ ( "parent1"
, Folder
{ folderName = "parent1"
, childFolders =
Dict.fromList
[ ( "child1"
, Folder
{ folderName = "child1", childFolders = Dict.empty }
)
, ( "child2"
, Folder
{ folderName = "child2", childFolders = Dict.empty }
)
, ( "child3"
, Folder
{ folderName = "child3"
, childFolders =
Dict.fromList
[ ( "sub-child_of_child3"
, Folder
{ folderName = "sub-child_of_child3"
, childFolders = Dict.empty }
)
]
}
)
]
}
)
]
main =
text <| toString <|
insertFolder
"parent1/child3/sub-child_of_child3"
"DynamicallyCreated"
fileSystem
导入Html(文本)
导入Dict(Dict)
----类型
类型别名FolderName=String
类型文件夹
=文件夹
{folderName:folderName
,子文件夹:文件系统
}
类型别名文件系统=
Dict FolderName文件夹
{主要功能:
获取路径中的第一个元素
并尝试对文件系统的子文件执行递归更新
-}
insertFolder:String->FolderName->FileSystem->FileSystem
insertFolder路径newFolderName文件系统=
让
nodeList=String.split“/”路径
在里面
案例节点列表
节点::rest->
--如果我们有节点,对文件夹进行递归更新
文件系统
|>Dict.update节点(Maybe.map
--没有路径,因此新文件夹必须是根文件夹
文件系统
|>Dict.inset newFolderName(newFolder newFolderName)
{-发生魔术的递归更新函数
-}
updateNestedFolder:FolderName->List FolderName->Folder->Folder
updateNestedFolder newFolderName节点列表(文件夹{folderName,childFolders})=
案例节点列表
下一级::rest->
--只要有一个节点列表,我们就试图找到更深层次的节点
让
--对子对象执行递归更新
newChildFolders=
子文件夹
|>Dict.updatenextlevel(Maybe.map
--这是最低级别,所以我们需要添加到这个文件系统中
让
--将newFolderName添加到子文件夹
newChildFolders=
子文件夹
|>Dict.insert newFolderName(newFolder newFolderName)
在里面
--返回文件夹
文件夹
{folderName=folderName
,childFolders=newChildFolders
}
----助手
{-创建一个没有任何子文件夹的新文件夹-}
新建文件夹:字符串->文件夹
NewFolderFolderName=
文件夹
{folderName=folderName
,childFolders=Dict.empty
}
------范例
文件系统=
口述从句表
[(“父母1”
,文件夹
{folderName=“parent1”
,子文件夹=
口述从句表
[(“儿童1”
,文件夹
{folderName=“child1”,childFolders=Dict.empty}
)
,(“儿童2”
,文件夹
{folderName=“child2”,childFolders=Dict.empty}
)
,(“儿童3”
,文件夹
{folderName=“child3”
,子文件夹=
口述从句表
[(“儿童3的子儿童”
,文件夹
{folderName=“子女3的子子女”
,childFolders=Dict.empty}
)
]
}
)
]
}
)
]
主要=
text上面给出的答案是有效的-但是如果你有一个围绕这个想法的问题(不一定是dicts)-很值得研究拉链是如何工作的
齐佩