F# OCaml关于列表的简单练习
各位早上好, 我必须做一个编程练习,但我被卡住了 这个练习需要一个函数,给定一个不为空的整数列表,返回出现次数最多的第一个数字 例如:F# OCaml关于列表的简单练习,f#,ocaml,F#,Ocaml,各位早上好, 我必须做一个编程练习,但我被卡住了 这个练习需要一个函数,给定一个不为空的整数列表,返回出现次数最多的第一个数字 例如: 模式[1;2;5;1;2;3;4;5;5;4:5;5]=>5 模式[2;1;2;1;1;2]=>2 模式[-1;2;1;2;5;-1;5;5;2]=>2 模式[7]==>7 重要:练习必须在函数式编程中进行 我的想法是: let rec occurences_counter xs i = match xs with
- 模式[1;2;5;1;2;3;4;5;5;4:5;5]=>5
- 模式[2;1;2;1;1;2]=>2
- 模式[-1;2;1;2;5;-1;5;5;2]=>2
- 模式[7]==>7
let rec occurences_counter xs i = match xs with
|[] -> failwith "Error"
|x :: xs when x = i -> 1 + occurences_counter xs i
|x :: xs -> occurences_counter xs i;;
在这个函数中,我被卡住了:
提前感谢,我是编程和stackoverflow方面的新手
对不起,我的英语不好一个解决方案是:首先计算一个夫妇列表(数量、发生次数)。 提示:使用List.assoc
然后,循环该对列表以查找最大出现次数,然后返回数字。您需要处理输入列表,同时维护一个状态,该状态存储每个数字的出现次数。基本上,状态可以是一个
映射
,其中键位于列表元素的域中,值位于自然数的域中。如果您将使用Map
,则算法将具有O(NlogN)
复杂性。您还可以使用关联列表(即类型为('key,'value)列表的列表
)来实现映射。这将导致二次复杂性。另一种方法是使用哈希表或长度等于输入域大小的数组。两者都会给你一个线性复杂度
在收集统计数据(即,从元素到其出现次数的映射)之后,您需要浏览获奖者的集合,并选择列表中的第一个
在OCaml中,解决方案如下所示:
open Core_kernel.Std
let mode xs : int =
List.fold xs ~init:Int.Map.empty ~f:(fun stat x ->
Map.change stat x (function
| None -> Some 1
| Some n -> Some (n+1))) |>
Map.fold ~init:Int.Map.empty ~f:(fun ~key:x ~data:n modes ->
Map.add_multi modes ~key:n ~data:x) |>
Map.max_elt |> function
| None -> invalid_arg "mode: empty list"
| Some (_,ms) -> List.find_exn xs ~f:(List.mem ms)
corebuild test.byte --
算法如下所示:
[1;2;5;1;2;3;4;5;5;4;5]
stats={1=>2;2=>2;3=>1;4=>2;5=>5}
mods={1=>[3];2=>[1;2];5=>[5]}
core
库才能使用它。使用coretop
在顶级中使用此功能。或者corebuild
来编译它,如下所示:
open Core_kernel.Std
let mode xs : int =
List.fold xs ~init:Int.Map.empty ~f:(fun stat x ->
Map.change stat x (function
| None -> Some 1
| Some n -> Some (n+1))) |>
Map.fold ~init:Int.Map.empty ~f:(fun ~key:x ~data:n modes ->
Map.add_multi modes ~key:n ~data:x) |>
Map.max_elt |> function
| None -> invalid_arg "mode: empty list"
| Some (_,ms) -> List.find_exn xs ~f:(List.mem ms)
corebuild test.byte --
如果源代码存储在test.ml
中,则建议:
如果您之前对列表进行排序,您的算法可能会简化。这具有O(N log(N))复杂性。然后测量相同数字的最长序列
这是一个很好的策略,因为您可以将工作的困难部分委托给一个众所周知的算法 这可能不是最漂亮的代码,但下面是我提出的(F#)。首先,我将每个元素转换为中间格式。此格式包含元素本身、元素发生的位置和发生的数量
tx型
通过这个设置,我现在编写了两个附加函数。一个聚合函数,首先将每个元素转换为一个已发生的。T
,按x.element
对它们进行分组(结果是一个列表)。然后它使用内部列表上的List.reduce
,将发生在同一元素上的事件添加到一起。结果是一个列表,该列表只包含单个已发生项。T
,每个元素都有第一个位置和已发生项的数量
let聚合=
List.mapi(乐趣x->occurrent.create x i 1)
>>List.groupBy(有趣的occ->occ.Element)
>>List.map(乐趣(x,occ)->List.reduce.add occ)
现在可以使用该聚合函数实现不同的聚合逻辑。在您的情况下,您只需要出现次数最多、位置最低的一个。我编写了另一个函数来实现这一点
让最早发生=
List.sortWith(fun x y->(executed.compareOccurredPosition x y)*-1)>>List.head>>(fun x->x.Element)
一个音符<代码>已发生。compareOccurredPosition编写为按升序对所有内容进行排序。我认为人们期望它在默认情况下从最小的元素到最大的元素。因此,默认情况下,第一个元素将是出现次数最少且位置最大的元素。通过将其结果与-1
相乘,可以将该函数转换为降序排序函数。我这样做的原因是我可以使用List.head
。我也可以使用List.last
来获取最后一个元素,但我觉得最好不要为了获取最后一个元素而再次查看整个列表。最重要的是,您不希望出现。t
您希望元素本身,因此我打开元素来获取数字
一切都在行动
让ll=[
[1;2;5;1;2;3;4;5;5;4;5;5]
[2;1;2;1;1;2]
[-1;2;1;2;5;-1;5;5;2]
[7]
]
陆上通信线
|>List.map聚合
|>List.map最早出现
|>List.iter(printfn“%d”)
现在将打印此代码
5
2
2
7
它还有一些粗糙的边缘,比如
发生。如果尝试添加使用不同元素发生的事件,则添加将引发异常
List.head
为空列表抛出异常
在这两种情况下,都不会编写代码来处理这些情况或确保不会引发异常。您的代码中可能存在一个问题:x::mode l,因为mode l返回int而不是list。我想你应该把模式(x::l)。另一行上的修复相同。排序的可能重复不会给您带来任何好处。您仍然需要处理整个列表,并收集统计数据。事实上,它们被排序在这里是没有帮助的。排序将取消有关获取第一个数字的部分