使用整数列表,例如:
[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?
感谢您的时间。
答案 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 []