【问题标题】:Non decreasing list of lists列表的非递减列表
【发布时间】:2016-10-01 00:29:08
【问题描述】:

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

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 却退回 2?例如。应该是:[[1;2;3;5;6];[3];[2;5;6];[2]]
  • 那是我的一个错误。你是对的
  • 编辑了你的 Q 以反映缺失的问题 3. 你能整理一个隐居的版本吗?还是卡住了?

标签: f#


【解决方案1】:

由于已经有一个使用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  

【讨论】:

  • 很好,初始化也不需要人工Int32.MinValue
  • 完美运行!仍然试图弄清楚它是如何工作的。什么是 x 和 lls?我知道它们是函数的参数,但恐怕我不明白是什么
  • 这是黑魔法......如果你构建没有折叠的版本,一切都会清楚。但用非常简单的术语来说,它将列表分成头部和尾部,检查是否相等并在结果之前添加。折叠和折叠可以消除反感,因此它们很有用,但在您尝试学习回归时却没有用。
  • @YingYangz 我添加了一些解释。
【解决方案2】:

这与@s952163 给出的答案基本相同,但通过删除嵌套匹配可能更具可读性,并且通过添加比较函数来执行“打包”也更通用。

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]

【讨论】:

    【解决方案3】:

    我会使用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
    

    请注意,您必须进行清理,将最终列表添加到列表列表中,然后在完成折叠后反转完整的列表列表和每个子列表。

    【讨论】:

      猜你喜欢
      • 2020-07-20
      • 1970-01-01
      • 2013-02-24
      • 1970-01-01
      • 1970-01-01
      • 2021-02-09
      • 1970-01-01
      • 2021-09-22
      • 1970-01-01
      相关资源
      最近更新 更多