我想知道是否有人可以针对以下问题为我的代码提供更简化的解决方案或改进。
假设我们有一个树枝,树枝深度“d”我们想修剪这棵树,这样我们就可以在深度保留“n”枝条 d 然后在深度 d-1 的另外n个分支;然后另一个 n 分支在 d-2 等......
在我的解决方案中,我需要使用dictionary
来跟踪分支数量和ref
变量深度以跟踪和降低深度级别< / p>
非常有兴趣了解更简单,更优雅的解决方案,或任何改善我所拥有的提示/技巧
数据结构
type MultiTree = | MNode of int * list<MultiTree>
测试树
let Mtree2 = MNode (0,
[MNode (1,[MNode (2,[MNode (3,[])])]);
MNode (1,[MNode (2,[MNode (3,[])])]);
MNode (1,[MNode (2,[MNode (3,[])])]);
MNode (1,[MNode (2,[MNode (3,[])])]);
MNode (1,[MNode (2,[MNode (3,[])])]);
MNode (1,[MNode (2,[MNode (3,[])])])])
修剪树功能
let trimTree noLosses depth t=
let mlimit = ref depth
let dict = Dictionary()
let fn k =
match dict.TryGetValue(k) with
| true, l -> dict.[k] <- l + 1
|_ -> dict.Add(k,1)
if dict.[k] >= noLosses then mlimit := !mlimit - 1 else mlimit := !mlimit
let rec loop d t =
match t with
| MNode(i,sub) when d > !mlimit ->
fn !mlimit
MNode(i, List.map (loop (d+1)) [])
| MNode(i,sub) -> MNode(i, List.map (loop (d+1)) sub)
loop 1 t
let Mtree2trimmed = Mtree2 |> trimTree 3 2
结果
使用Thomas P的“printTree”功能,可以很好地显示
let printt tree =
let rec loop depth (MNode(n, sub)) =
printfn "%s %A" depth n
for s in sub do loop (depth + " ") s
loop "" tree
输出 -
printt Mtree2
0
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
输出 -
printt Mtree2trimmed
0
1
2
1
2
1
2
1
1
1
所以,如果你已经做到这一点 - 任何建议?
干杯!
答案 0 :(得分:1)
此问题称为mapreduce。基本方法如下:
让我们用补充值标记每个分支:
depth
(0
= topmost branch)sequential
(针对每个子树,以0
开头)为了实现这一点,我更改了树的定义,使其具有通用性:
type MultiTree<'T> = | MNode of 'T * list<MultiTree<'T>>
现在:
let rec mapper depth sequential = function
| MNode(value, sub) ->
MNode( (depth, sequential, value),
(sub |> List.mapi (fun i value -> mapper (depth+1) i value))
)
let tree1 = MNode (0,
[MNode (1,[MNode (2,[])]);
MNode (3,[]);])
printfn "Original data"
tree1 |> printt
printfn "Mapped data"
tree1 |> mapper 0 0 |> printt
结果将是:
Original data
0
1
2
3
Mapped data
(0, 0, 0)
(1, 0, 1)
(2, 0, 2)
(1, 1, 3)
现在,当数据被标记时,我们可以应用我们想要的任何过滤器。这里有三个例子,加上一个更大的树来展示所有可能性:
// Take only first n branches at every level
let rec filter1 n = function
// first subtrees pass (up to "noLosses" count)
| MNode( (depth, sequential, value), sub)
when sequential < n
-> Some(MNode(value, List.choose (filter1 n) sub))
// the rest are skipped
| _ -> None
// Take "d" levels of branches unchanged, at higher levels take only second branch
let rec filter2 d = function
| MNode( (depth, sequential, value), sub)
when depth < d // lower depth - pass
|| sequential = 1 // at higher levels, take only the second branch (=1)
-> Some(MNode(value, List.choose (filter2 d) sub))
// the rest are skipped
| _ -> None
// Take only first n branches at every level;
// "n" is a list to identify maximal element at each level
let rec filter3 ns ts =
match ns, ts with
// Empty "noLosse" list -> no value
| [], _ -> None
// if the sequential order of Tree branch is less than
// the corresponding value in "ns" list, let the value pass the filter
| nsHead :: nsTail, MNode((_, sequential, value), sub)
when sequential < nsHead -> Some(MNode(value, List.choose (filter3 nsTail) sub))
// the rest are skipped
| _, _ -> None
printfn "Original data"
tree2 |> printt
printfn "Filter1 applied"
tree2 |> mapper 0 0 |> filter1 2 |> Option.iter printt
printfn "Filter2 applied"
tree2 |> mapper 0 0 |> filter2 2 |> Option.iter printt
printfn "Filter3 applied"
tree2 |> mapper 0 0 |> filter3 [4; 4; 2] |> Option.iter printt
注意,我们需要Option.iter
,因为过滤器可能会返回None
值。
输出:
Original data
1
11
111
1111
1112
1113
12
121
1211
122
1221
1222
1223
123
124
13
131
1211
14
141
1411
15
151
1511
16
161
1611
Filter1 applied
1
11
111
1111
1112
12
121
1211
122
1221
1222
Filter2 applied
1
11
12
122
1222
13
14
15
16
Filter3 applied
1
11
111
12
121
122
13
131
14
141
重要的是,这种方法并未针对性能进行优化。它的主要思想是展示如何将任务拆分为一系列较小的任务,以便实际过滤实际上是一个简单的匹配案例。