如何计算OCaml中任何元素类型的列表中连续出现的次数?

问题描述

在OCaml中,假设我有一个字符串列表,如下所示:

let ls : string list = ["A"; "A"; "B"; "B"; "A"; "Y"; "Y"; "Y"] ;;

我在编写一个函数时遇到麻烦,该函数可以计算一个元素连续出现多少次,并且还可以将该元素与其频率配对。例如,给定上面的列表作为输入,该函数应返回[("A",2); ("B",2),("A",1),("Y",3)]

我尝试在其他地方寻找一些提示,但是几乎所有其他类似的操作都是使用int list完成的,可以很容易地简单地将数字加起来。但是在这里,我们不能添加字符串

我的直觉是使用fold_left之类的东西,如下所示:

let lis : int list = [1;2;3;4;5]
let count (lis : int list) = List.fold_left (fun x y -> x + y) (0) (lis)

实质上是从左到右累计所有元素。但是,就我而言,我不想累积所有元素的总和,我只需要计算一个元素连续出现的次数。一些建议将不胜感激!

解决方法

这显然是一项家庭作业,所以我只给出一些提示。

使代码正常工作时,不会将字符串(或任何其他类型)加在一起。它将整数加在一起。因此,您可能想再次在网上回顾一下这些示例:-)

您绝对可以使用fold_left来获得答案。首先,请注意结果是成对的列表。每对的第一个元素可以是任何类型,具体取决于原始列表的类型。每对中的第二个元素是一个int。因此,您有一个正在使用的基本类型:('a * int) list

想象一下,您有办法“增加”这样的列表:

let increment (list: ('a * int) list) value =
     (* This is one way to think of your problem *)

此函数在列表中查找第一个元素等于value的对。如果找到它,它将返回一个新列表,其中关联的int比以前大一个。如果找不到,它将返回一个带有附加元素(value,1)的新列表。

这是您要折叠到列表上的基本操作,而不是示例代码的+操作。