不减少的列表清单

时间:2016-10-01 00:29:09

标签: f#

我一直在尝试实现一个获取整数列表的函数,然后返回一个非递减整数列表。 即

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 ->

我将如何使用模式匹配创建子列表? 或者我错误地接近了这个问题?

3 个答案:

答案 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>