F# F中fold的正确使用#
我是新来的。我正在尝试使用List.fold帮助我根据类别和子类别的Id和ParentId字段生成类别和子类别的列表。看起来我可能使这段代码比需要的更复杂,因为我得到了stackoverflow错误。我做错了什么或错过了什么?感谢所有相关反馈F# F中fold的正确使用#,f#,F#,我是新来的。我正在尝试使用List.fold帮助我根据类别和子类别的Id和ParentId字段生成类别和子类别的列表。看起来我可能使这段代码比需要的更复杂,因为我得到了stackoverflow错误。我做错了什么或错过了什么?感谢所有相关反馈 // types type CategoryStructure = { Id: ValidString; ParentId: ValidString; Name: ValidString; Abbreviation: Val
// types
type CategoryStructure = {
Id: ValidString;
ParentId: ValidString;
Name: ValidString;
Abbreviation: ValidString;
Description: ValidString;
SapId: ValidString;
Section: ValidString;
SectionPosition: ValidString
}
type DynamicCategories = {
Category: CategoryStructure;
SubCategories: seq<DynamicCategories>
}
// this is the function that produces the stack overflow error
let rec private structureCategories (fullList: CategoryStructure list)
(list: CategoryStructure list) =
List.fold (fun acc elem ->
// get all categories and details
let categories = fullList
let mainAcc =
[
for row in categories do
if row = elem
then
let subs =
List.fold (fun acc' elem' ->
if row.Id = elem'.ParentStructureId
then
let foundSubCategory =
{
Category = elem';
SubCategories = structureCategories fullList list |> Seq.ofList
}
foundSubCategory :: acc'
else acc'
) List.empty<DynamicCategories> categories
|> Seq.ofList
yield{
Category = elem;
SubCategories = subs
}
]
mainAcc @ acc
) List.empty<DynamicCategories> list
// this function gets the initial parent categories and calls the above function
let getStructuredCategories () =
let categories = allCategoriesAndDetails () |> List.ofSeq
[
for row in categories do
if row.ParentStructureId = NotValid
then yield row
] |> structureCategories categories |> Seq.ofList
//类型
类型类别结构={
Id:有效字符串;
ParentId:ValidString;
名称:ValidString;
缩写:ValidString;
描述:有效字符串;
SapId:有效;
第节:有效期;
分区位置:有效字符串
}
类型DynamicCategories={
类别:类别结构;
子类别:seq
}
//这是产生堆栈溢出错误的函数
let rec private structureCategories(完整列表:类别结构列表)
(列表:类别结构列表)=
List.fold(趣味acc元素->
//获取所有类别和详细信息
让类别=完整列表
让我来=
[
对于类别中的行,请执行以下操作:
如果行=元素
然后
设subs=
List.fold(趣味acc'elem'->
如果row.Id=elem.ParentStructureId
然后
设子类别=
{
类别=元素';
子类别=结构类别完整列表|>序列列表
}
foundSubCategory::acc'
否则acc'
)列表。空类别
|>顺序列表
屈服{
类别=要素;
子类别=子类别
}
]
mainAcc@acc
)列表。空列表
//此函数获取初始父类别并调用上述函数
让getStructuredCategories()=
让categories=allCategoriesAndDetails()|>List.ofSeq
[
对于类别中的行,请执行以下操作:
如果row.ParentStructureId=无效
然后让行
]|>结构类别类别|>列表顺序
您继续使用相同的参数调用结构类别
,完整列表
和列表
。因为参数是相同的,所以它继续执行与上一个过程完全相同的操作,并使用相同的参数再次调用自己。等等
这是无界递归(“无界”在这里的意思是“不知道什么时候停止循环”),也不是“尾部递归”,所以很自然,它会导致堆栈溢出
如果要将平面列表转换为树状结构,可以执行比此简单一点的操作:
let getChildren fullList parentId = fullList |> List.filter (fun c -> c.ParentId = parentId)
let rec toTree fullList root =
{ Category = root;
SubCategories =
getChildren fullList root.Id
|> List.map (toTree fullList) }
这样,您将面临两个问题,如果不进一步了解您的需求,我不知道如何解决这两个问题:
ParentId
来表示,但从您的数据结构来看,“empty”的含义并不清楚最后,这个天真的解决方案虽然比您原来的解决方案好,但仍然比需要的慢一些。它在整个列表上迭代一次,对每个节点执行另一次传递以确定其子节点,从而导致总体复杂性为O(N^2)。如果您期望相对较小的列表,这可能很好,但对于较大的列表则不太好。在这种情况下,我会首先将列表转换为哈希表(由
ParentId
键入),然后使用该哈希表来查找子项,而不是list.filter
使用相同的参数继续调用structureCegories
,fullList
和list
。因为参数是相同的,所以它继续执行与上一个过程完全相同的操作,并使用相同的参数再次调用自己。等等
这是无界递归(“无界”在这里的意思是“不知道什么时候停止循环”),也不是“尾部递归”,所以很自然,它会导致堆栈溢出
如果要将平面列表转换为树状结构,可以执行比此简单一点的操作:
let getChildren fullList parentId = fullList |> List.filter (fun c -> c.ParentId = parentId)
let rec toTree fullList root =
{ Category = root;
SubCategories =
getChildren fullList root.Id
|> List.map (toTree fullList) }
这样,您将面临两个问题,如果不进一步了解您的需求,我不知道如何解决这两个问题:
ParentId
来表示,但从您的数据结构来看,“empty”的含义并不清楚最后,这个天真的解决方案虽然比您原来的解决方案好,但仍然比需要的慢一些。它在整个列表上迭代一次,对每个节点执行另一次传递以确定其子节点,从而导致总体复杂性为O(N^2)。如果您期望相对较小的列表,这可能很好,但对于较大的列表则不太好。在这种情况下,我会首先将列表转换为一个哈希表(由
ParentId
键入),然后使用该哈希表来查找子项,而不是列表。过滤器多亏了Fyodor,我发现了我的错误。他对提出同样的论点一窍不通。我在之前添加了这段代码
let foundSubCategory =
{
Category = elem';
SubCategories = structureCategories fullList modifiedList |> Seq.ofList
}
let getStructuredCategories () =
let fullList = allCategoriesAndDetails ()
let parentList () =
allCategoriesAndDetails ()
|> Seq.filter (fun p -> p.ParentStructureId = NotValid)
let rec toTree (fullList': seq<CategoryStructure>) (parent: CategoryStructure) =
fullList'
|> Seq.filter (fun x -> x.ParentStructureId = parent.Id)
|> Seq.map (fun x ->
{
Category = x;
SubCategories =
toTree fullList' x
})
seq {
for row in parentList () do
yield {
Category = row;
SubCategories = toTree fullList row
}
}