我想知道如何编写一个函数:'a list*int -> 'a list*list
将给定列表转换为给定最大长度的列表列表。
例如:segments( [1;2;3;4;5;6;7;8;9], 2 ) => [ [1;2]; [3;4]; [5;6]; [7;8]; [9] ]
答案 0 :(得分:4)
这是一个尾递归解决方案:
let segments xs n =
let rec loop n xs (count, elem) acc =
match xs with
| x::xs' when count < n -> loop n xs' (count+1, x::elem) acc
| x::xs' -> loop n xs' (1, [x]) ((List.rev elem)::acc)
| [] -> List.rev ((List.rev elem)::acc) in
loop n xs (0, []) []
这个想法是保留一个用于创建当前段的累加器和另一个用于存储段列表的累加器。
答案 1 :(得分:0)
let rec segments list n =
try let head, tail = BatList.split_at n list in
head :: segments tail n
with Invalid_index _ -> [ list ]
如果您无法访问电池,实施split_at
相当容易。
答案 2 :(得分:0)
我不同意使用BatList应该用于此。当然,如果你和那些习惯使用这些库的人一起编程,那就太棒了(也许你是,那么请忽略它!)。但是在“经典”情况下,使用简单的尾递归函数可以更自然地完成。 (你可以折叠附加以获得一些无聊的东西,但这在实践中不能很好地工作,并且有一个更好的基于累加器的解决方案,允许基于尾部调用的简单实现。)
答案 3 :(得分:0)
之前正确答案的改进版本(通过打击垫):
let segments (xs,n) =
let rec loop xs (count, elem) acc =
match xs with
| x::xs' when count < n -> loop xs' (count+1, x::elem) acc
| x::xs' -> loop xs' (1, [x]) ((List.rev elem)::acc)
| [] -> List.rev ((List.rev elem)::acc) in
loop xs (0, []) [];;