如何用F#的seq.groupby和seq.fold创建树形结构?
问题描述
我需要创建一个能在WPF中展示的树形结构,类型定义如下:
type BranchDate = {Id: Guid; PostingDate: DateTime} type LedgerRecord = { rid: Guid DebitCredit: string option PostingTime: DateTime option BillTo: string option CptCode: string option Description: string option Charge: double option CheckNum: string option PaymentMethod: string option Paid: double option Refiled: double option EncounterInsuranceId : int option CptId: int option } type Tree = | Branch of BranchDate * Tree list | Leaf of LedgerRecord
从数据库获取的LedgerRecord序列为seq<LedgerRecord>,我尝试实现的代码如下,但无法完成:
let MakeTree (p:LedgerRecord[] option) : Tree = let insert tree = raise <| NotImplementedException() let makeBranch (d:DateTime) (v:seq<LedgerRecord>) : Tree = Branch ({Id = Guid.NewGuid(); PostingDate = d}, v |> Seq.map (fun q -> Leaf q) |> Seq.toList) let root = Branch ( {Id=Guid.NewGuid(); PostingDate = new DateTime(01,01,01)}, [] ) let ggg = match p with | None -> failwith "Branch ( {Id=Guid.NewGuid(); PostingDate = new DateTime(01,01,01)}, [] )" | Some pp -> pp |> Seq.groupBy (fun t -> Option.get t.PostingTime) |> Seq.map (fun (k,v) -> makeBranch k v) let hhh = Seq.fold insert root ggg hhh
我不清楚如何编写insert函数来生成符合要求的树形结构,最终在WPF中要展示成这样的形式:
1/1/1919 shirt pants shoes 2/3/1956 carpet heater dog food
解决方案
你的思路已经很接近目标,根本不需要复杂的insert函数——你已经通过groupBy完成了同日期记录的分组,并用makeBranch创建了对应日期的分支节点,只需将这些分支直接作为根节点的子节点列表即可,无需逐个插入。
修改后的完整代码如下:
let MakeTree (p:LedgerRecord[] option) : Tree = let makeBranch (d:DateTime) (v:seq<LedgerRecord>) : Tree = Branch ({Id = Guid.NewGuid(); PostingDate = d}, v |> Seq.map Leaf |> Seq.toList) match p with | None -> // 无记录时返回空根节点 Branch ({Id=Guid.NewGuid(); PostingDate = DateTime(1,1,1)}, []) | Some pp -> let dateBranches = pp |> Seq.groupBy (fun t -> // 处理PostingTime为空的情况,避免Option.get抛出异常 match t.PostingTime with | Some dt -> dt.Date // 按日期分组,忽略时分秒差异 | None -> DateTime(1,1,1) // 无日期的记录归到默认根分支下 ) |> Seq.map (fun (k,v) -> makeBranch k v) |> Seq.toList // 将所有日期分支作为根节点的子节点 Branch ({Id=Guid.NewGuid(); PostingDate = DateTime(1,1,1)}, dateBranches)
关键调整说明
- 移除了冗余的
insert函数和Seq.fold操作,直接将分组后的分支列表赋值给根节点的子节点集合 - 增加了
PostingTime为None的异常处理逻辑,避免空值报错 - 改用
DateTime.Date分组,确保同一天(时分秒不同)的记录会被归到同一个分支下
这样生成的树形结构完全匹配你需要的WPF展示形式:根节点下是各个日期分支,每个日期分支下对应具体的记录叶子节点。
内容的提问来源于stack exchange,提问作者Alan Wayne
相关产品推荐
相关产品推荐

