我目前想知道根据给定标准拆分子列表中的列表的方法。由于这项工作的教学目的,我不使用内置函数。 IE,下面的程序应该给出一个列表,返回一个列表列表,其中每个子列表没有重复项并按升序排列:
increment [4;4;10;20;5;30;6;10] = [[4;10;20];[5;30];[6;10]]
increment [5;6;4;3;2;1] = [[5;6];[4];[3];[2];[1]]
到目前为止,我最好的尝试是基于我制作的这一大块代码:
let rec increment li [lo] =
match li with
|[] -> [lo]
|[x] -> [x]::[lo]
|x::y::xs -> if x = y then
increment (y::xs) [lo]
elif x < y then
x::(increment (y::xs) [lo])
else
(x::(increment xs [lo]))::[lo]
不幸的是,我无法创建列表列表。原则是正确的。它基于我构建的函数,正确隔离升序列表(如果存在):
let rec incrementAux li =
match li with
|[] -> []
|[x] -> [x]
|x::y::xs -> if x = y then
incrementAux (y::xs)
elif x < y then
x::(incrementAux (y::xs))
else
x::(incrementAux [])
任何建议都将受到高度赞赏!
答案 0 :(得分:3)
如果您想在不使用List
模块上的内置函数的情况下执行此操作(纯粹作为学习练习),那么您只需了解map
和fold
即可你可以自己实现它们。我会从this wikipedia article开始。方便的是,您可以根据rev
轻松实施fold
,这样就不会有问题。一旦你理解了每个函数的作用,就可以自己实现它们:
let rec fold f state = function
| [] -> state
| head::tail -> fold f (f state head) tail
let map f list =
[for item in list -> f item]
let rev list =
fold (fun acc cur -> cur::acc) [] list
然后,您可以在Szer的解决方案中用自己的函数替换内置函数:
let input = [4;4;10;20;5;30;6;10]
let output = [[4;10;20];[5;30];[6;10]]
let increment =
fold (fun (last::rest as total) x ->
match last with
| [] -> [x] :: rest
| h::_ as last ->
if x > h then (x::last)::rest
else if x = h then total
else [x]::total) [[]]
>> map rev
>> rev
let testOutput = increment input
testOutput = output
请注意,fold
的此实现与F#List
的实现方式不同。这是基于维基百科文章中的简单Haskell示例。功能是相同的,但实现是完全不同的,因为F#实际上使用可变累加器和for循环。
答案 1 :(得分:1)
你可以在没有递归的情况下做到这一点。带有一点记忆的List.fold
可以提供帮助:
let input = [4;4;10;20;5;30;6;10]
let output = [[4;10;20];[5;30];[6;10]]
let increment =
List.fold (fun (last::rest as total) x ->
match last with
| [] -> [x] :: rest
| h::_ as last ->
if x > h then (x::last)::rest
else if x = h then total
else [x]::total) [[]]
>> List.map List.rev
>> List.rev
let testOutput = increment input
testOutput = output // true