我一直在尝试实现一个获取整数列表的函数,然后返回一个非递减整数列表。 即
let ls = [ 1;2;3;5;6;3;2;5;6;2]
I should get [[1;2;3;5;6];[3];[2;5;6];[2]]
我该如何处理?我是功能编程的总菜鸟。
我能想到所需的步骤: 1.启动一个新的子列表,将每个元素与旁边的元素进行比较。如果它更大,那么添加到列表。如果没有,请开始一个新的清单等等。
从迄今为止我从f#函数编程一书中学到的(我刚刚开始几天),我可以使用模式匹配和递归函数来查看比较两个元素的列表 像这样的东西:
let rec nonDecreasing list =
match list with
| (x,y) :: xs when x <= y ->
我将如何使用模式匹配创建子列表? 或者我错误地接近了这个问题?
答案 0 :(得分:4)
由于已经有使用fold
的解决方案,所以这是使用foldBack
的另一个答案,因此您无需撤消它。现在您可以退出纯粹的递归解决方案。
let splitByInc x lls = // x is an item from the list, lls is a list of lists
match lls with
| y::xs -> // split the list of lists into head and tail
match y with
| h::_ when x <= h -> (x::y)::xs // take the head, and compare it with x, then cons it together with the rest
| _ -> [x]::lls // in the other case cons the single item with the rest of the list of lists
| _ -> [[x]] // nothing else to do, return the whole thing
let ls = [ 1;2;3;5;6;3;2;5;6;3]
List.foldBack splitByInc ls [] //foldBack needs a folder function, a list and a starting state
修改强>
这是一个非常简化的示例,您可以编写递归总和并将其与折叠版本进行比较:
let sumList x y =
x + y
List.foldBack sumList ls 0 //36
为了更好地理解splitByInc的作用,请尝试使用以下示例:
splitByInc 4 [[5;6;7]] // matches (x::y)::xs
splitByInc 4 [] // matches [[x]]
splitByInc 4 [[1;2;3]] // matches [x]::lls
答案 1 :(得分:3)
这与@s952163给出的答案基本相同,但通过删除嵌套匹配可能更具可读性,并且通过添加比较函数来进行更为通用的#34; packing&#34 ;
let packWhile predicate list =
let folder item = function
| [] -> [[ item ]]
| (subHead :: _ as subList) :: accTail
when predicate item subHead -> (item :: subList) :: accTail
| accList -> [ item ] :: accList
List.foldBack folder list []
// usage (you can replace (<=) by (fun x y -> x <= y) if it's clearer for you)
packWhile (<=) [1;2;3;5;6;3;2;5;6;3]
// you can also define a function to bake-in the comparison
let packIncreasing list = packWhile (<=) list
packIncreasing [1;2;3;5;6;3;2;5;6;3]
答案 2 :(得分:2)
我使用fold
,其中'State
是一个元组,其中包含您之前的值,列表列表以及您正在处理的当前非递减列表
let ls = [ 1;2;3;5;6;3;2;5;6;3]
let _, listOfLists, currList =
((Int32.MinValue, [], []), ls) ||>
List.fold(fun (prev, listOfLists, currList) t ->
if t < prev then //decreasing, so store your currList and start a new one
t, currList::listOfLists, [t]
else //just add t to your currList
t, listOfLists, t::currList)
let listOfLists = currList::listOfLists //cleanup: append final sublist
let final = List.rev(List.map List.rev listOfLists) //cleanup: reverse everything
printfn "%A" final
请注意,您必须清理,将最终列表添加到列表列表中,然后在完成折叠后撤消完整的列表列表和每个子列表。< / p>