Ocaml列表的int列表(相反的扁平化)

时间:2012-11-07 01:35:16

标签: list functional-programming split ocaml

使用整数列表,例如:

[1;2;3;4;5;6;7;8;9]

如何从上面创建一个int列表列表,所有新列表都具有相同的指定长度?

例如,我需要来自:

[1;2;3;4;5;6;7;8;9] to [[1;2;3];[4;5;6];[7;8;9]]

要分割的数字是3?

感谢您的时间。

4 个答案:

答案 0 :(得分:3)

所以你真正想要的是类型

的功能
val split : int list -> int -> int list list

获取整数列表和子列表大小。一个更普遍的怎么样?

val split : 'a list -> int -> 'a list list

以下是实施:

let split xs size =
  let (_, r, rs) =
    (* fold over the list, keeping track of how many elements are still
       missing in the current list (csize), the current list (ys) and
       the result list (zss) *) 
    List.fold_left (fun (csize, ys, zss) elt ->
      (* if target size is 0, add the current list to the target list and
         start a new empty current list of target-size size *)
      if csize = 0 then (size - 1, [elt], zss @ [ys])
      (* otherwise decrement the target size and append the current element
         elt to the current list ys *)
      else (csize - 1, ys @ [elt], zss))
      (* start the accumulator with target-size=size, an empty current list and
         an empty target-list *)
        (size, [], []) xs
  in
  (* add the "left-overs" to the back of the target-list *)
  rs @ [r]

如果您获得额外积分,请告诉我们! ;)

答案 1 :(得分:2)

您提供的代码是一种从列表前面删除给定数量元素的方法。一种方法可能是保持这个功能不变(可能会稍微清理一下)并使用外部函数来处理整个列表。为了使其易于使用,您的函数可能还希望返回列表的其余部分(因此外部函数可以轻松地告诉仍需要分段的内容)。

但是,您似乎想用单个函数解决问题。如果是这样的话,我发现缺少的主要是你已经剪掉的碎片的累加器。当你达到你的计数时你也不能放弃,你必须记住你刚刚剪掉的那一块,然后以同样的方式处理剩下的列表。

如果我自己解决这个问题,我会尝试概括问题,以便递归调用可以在所有情况下都有所帮助。可能有用的东西是让第一件比其他件短。这样你就可以把它写成一个单独的函数,没有累加器 (只是递归调用)。

答案 2 :(得分:2)

我可能会这样做:

    let split lst n =
      let rec parti n acc xs = 
        match xs with 
        | []              -> (List.rev acc, [])
        | _::_ when n = 0 -> (List.rev acc, xs)
        | x::xs -> parti (pred n) (x::acc) xs
      in let rec concat acc = function
        | [] -> List.rev acc
        | xs -> let (part, rest) = parti n [] xs in concat (part::acc) rest
      in concat [] lst

请注意,如果n没有平均分配List.length lst,我们就会宽容。 例: split [1;2;3;4;5] 2提供[[1;2];[3;4];[5]]

最后注意:代码非常冗长,因为OCaml标准库非常简单:/使用不同的lib我确信这可以更加简洁。

答案 3 :(得分:1)

let rec split n xs =
  let rec take k xs ys = match k, xs with
    | 0, _ -> List.rev ys :: split n xs
    | _, [] -> if ys = [] then [] else [ys]
    | _, x::xs' -> take (k - 1) xs' (x::ys)
  in take n xs []