根据您的示例,我不确定我是否理解问题。 如果您正在尝试查找重复值的序列,这非常简单。让我们看一下List.fold_left的解决方法。
List.fold_left
(fun (max_seq, cur_seq) x ->
match (max_seq, cur_seq) with
(* Set the info up on the first iteration. *)
| None, None -> (Some (1, x), Some (1, x))
(* These should basically never occur. *)
| None, Some (cur_len, cur_val) -> (cur_seq, cur_seq)
| Some (max_len, max_val), None -> (max_seq, max_seq)
(* Where the real magic happens. *)
| Some (max_len, max_val), Some (cur_len, cur_val) ->
if x = cur_val && cur_len >= max_len then
let new_val = Some (cur_len + 1, cur_val) in
(new_val, new_val)
else if x = cur_val then
(max_seq, Some (cur_len + 1, cur_val))
else
(max_seq, Some (1, x))
)
(None, None)
[1; 1; 5; 7; 2; 2; 2; 2; 2; 2; 8; 8; 1; 1; 1; 1; 1]
结果:
(Some (6, 2), Some (5, 1))
因为我们需要处理空列表的前景,我们将使用option 类型来表示表示观察到的最大序列以及我们正在跟踪的当前序列的元组。
鉴于当我们观察到两个值都是None 时,我们将最大序列和当前序列都设置为迄今为止观察到的唯一值,序列长度为1,接下来的两种情况基本上只是为了确保详尽无遗匹配:
| None, Some (cur_len, cur_val) -> (cur_seq, cur_seq)
| Some (max_len, max_val), None -> (max_seq, max_seq)
真正的魔法发生在这里:
| Some (max_len, max_val), Some (cur_len, cur_val) ->
if x = cur_val && cur_len >= max_len then
let new_val = Some (cur_len + 1, cur_val) in
(new_val, new_val)
else if x = cur_val then
(max_seq, Some (cur_len + 1, cur_val))
else
(max_seq, Some (1, x))
当我们折叠列表中的每个值时:
-
如果它是当前序列的延续,并且长度与最大序列相同或大于最大序列,那么我们就有一个新最大序列。
-
否则,我们有一个序列的延续,但它不是一个新的最大值。
-
否则,我们要跟踪一个新序列。
最终结果将给出两个值,分别代表最大序列长度和值,以及当前序列和值。我们可以使用模式匹配来提取这些信息并剔除我们需要的信息。
例如:
let max_seq lst =
let (max, _) = List.fold_left
(fun (max_seq, cur_seq) x ->
match (max_seq, cur_seq) with
| None, None -> (Some (1, x), Some (1, x))
| None, Some (cur_len, cur_val) -> (cur_seq, cur_seq)
| Some (max_len, max_val), None -> (max_seq, max_seq)
| Some (max_len, max_val), Some (cur_len, cur_val) ->
if x = cur_val && cur_len >= max_len then
let new_val = Some (cur_len + 1, cur_val) in
(new_val, new_val)
else if x = cur_val then
(max_seq, Some (cur_len + 1, cur_val))
else
(max_seq, Some (1, x))
)
(None, None)
lst
in
max
现在我们可以简单地在列表中调用它。
utop # max_seq [1; 1; 5; 7; 2; 2; 2; 2; 2; 2; 8; 8; 1; 1; 1; 1; 1];;
- : (int * int) option = Some (6, 2)
作为该语言的新手,如果它可以帮助您理解List.fold_left,那么它是一个非常容易实现的功能,并且当您试图围绕它进行思考时,查看该实现通常很有用。我将调用我的版本foldl。
let rec foldl f init lst =
match lst with
| [] -> init
| x::xs -> foldl f (f init x) xs