2

使用整数列表,例如:

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

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

例如,我需要从:

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

要拆分的数字是 3?

谢谢你的时间。

4

4 回答 4

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]

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

于 2012-11-07T21:27:19.313 回答
2

您提供的代码是一种从列表前面删除给定数量元素的方法。继续的一种方法可能是保留此函数(可能稍微清理一下)并使用外部函数来处理整个列表。为了让这个工作更容易,你的函数可能还想返回列表的其余部分(这样外部函数可以很容易地判断出仍然需要分段的内容)。

不过,您似乎想用一个函数来解决问题。如果是这样,我看到的主要缺失是您已经剪掉的碎片的累加器。而且你也不能在达到计数时退出,你必须记住你刚刚剪下的部分,然后以同样的方式处理列表的其余部分。

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

于 2012-11-07T02:37:24.463 回答
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 标准库非常简单:/ 使用不同的库,我相信这可以更简洁。

于 2012-11-07T03:20:27.013 回答
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 []
于 2012-11-08T07:36:30.247 回答