我想创建一个 rec 函数,比如 oddleninLdbl
,它将列表 "L" 作为参数,并返回 "L" 的副本strong> 其中奇数长度的列表已“加倍” - 这里加倍意味着列表将与自身连接。
为了说明上述内容,我们的想法是:
oddleninLdbl [[]; [5]; [23;5]; [45;65;2]; []; [34;85;7;22;1]];;
返回以下内容:
[[]; [5;5]; [23;5]; [45;65;2;45;65;2]; []; [34;85;7;22;1;34;85;7;22;1]]
它也应该适用于任何列表类型,例如这里的字符串:
oddleninLdbl [[]; ["mi";"lo"]; ["la"]; ["lo";"co";"mo"]]
应该返回:
[[]; ["mi";"lo"]; ["la";"la"]; ["lo";"co";"mo";"lo";"co";"mo"]]
我一直在绕着这个转一圈。如果我没记错的话,我知道我的“if 表达式”应该围绕与列表中列表长度相关的内容,当它是 List.length mod 2 = 1
时,子列表应该与自身连接。>
但是,我无法应用它,因为我从未使用过列表列表!这个函数应该怎么写?非常感谢您的帮助。
编辑 1:
我已尝试执行以下操作
let double_list l = l@l;;
let rec oddleninLdbl l =
if l = []
then []
else (
let t = List.tl l in
if ((List.length l) mod 2 = 1)
then double_list l
else oddleninLdbl t
) ;;
但我得到这个作为答案:
# oddleninLdbl [[]; [5]; [23;5]; [45;65;2]; []; [34;85;7;22;1]] ;;
- : int list list =
[[5]; [23; 5]; [45; 65; 2]; []; [34; 85; 7; 22; 1]; [5]; [23; 5]; [45; 65; 2]; []; [34; 85; 7; 22; 1]]
# oddleninLdbl [[]; ["mi";"lo"]; ["la"]; ["lo";"co";"mo"]] ;;
- : string list list =
[["mi"; "lo"]; ["la"]; ["lo"; "co"; "mo"]; ["mi"; "lo"]; ["la"];["lo"; "co"; "mo"]]
# oddleninLdbl [5;6;3;4;6] ;;
- : int list = [5; 6; 3; 4; 6; 5; 6; 3; 4; 6]
# oddleninLdbl [4;5] ;;
- : int list = [5; 5]
# oddleninLdbl [4;5;8] ;;
- : int list = [4; 5; 8; 4; 5; 8]
# oddleninLdbl [4;5;8;9] ;;
- : int list = [5; 8; 9; 5; 8; 9]
# oddleninLdbl ["mi";"lo"] ;;
- : string list = ["lo"; "lo"]
# oddleninLdbl ["mi";"lo";"co"] ;;
- : string list = ["mi"; "lo"; "co"; "mi"; "lo"; "co"]
# oddleninLdbl ["mi"] ;;
- : string list = ["mi"; "mi"]
显然不是这个函数所期望的。我的代码中的罪魁祸首在哪里?有人可以给我他们的诊断吗?
编辑 2:
let double_list l = (List.hd l)@(List.hd l);;
let p l = (List.length (List.hd l)) mod 2 = 1 ;;
let apply p double_list l =
let rec aux acc l = match l with
| [] -> List.rev acc
| hd :: tl ->
let hd = if p hd then double_list hd else hd in
aux (hd :: acc) tl ;;
我在这个问题上遇到了语法错误,我在这里跳过了一些东西。你怎么看?
答案 0 :(得分:1)
处理不易理解的结构时,一个好的经验法则是分而治之。
您的问题在这里可以分解为多个部分:
所以,你应该首先创建一个简单的函数来将列表加倍
let double_list l = (* double the elements in a list of elements *)
然后你应该创建一个函数来遍历元素列表并在当前元素对应于谓词p
时做一些事情
let apply p f l =
let rec aux acc l = match l with
| [] -> List.rev acc
| hd :: tl ->
let hd = if p hd then f hd else hd in
aux (hd :: acc) tl
in aux [] l
现在您唯一需要的是正确的谓词 p
并且您已经实现了您的函数 f
,它应该可以完美运行。
总而言之,当您可以通过将问题分解为更小的问题来简化问题时,永远不要害怕表面上的复杂性。
编辑:
这是您的代码:
let double_list l = l@l;;
let rec oddleninLdbl l =
if l = []
then []
else (
let t = List.tl l in
if ((List.length l) mod 2 = 1)
then double_list l
else oddleninLdbl t
) ;;
这不是惯用的 OCaml,请尝试使用模式匹配:
let double_list l = l@l;;
let rec oddleninLdbl l =
match l with
| [] -> []
| hd :: tl ->
if ((List.length l) mod 2 = 1)
then double_list l
else oddleninLdbl tl;;
如您所见,您正在检查 l
是否为奇数,而不是其元素,这不是您想要做的。您想检查 hd
是否为奇数并将其加倍,然后继续遍历列表的其余部分并将 hd
(加倍或不加倍)附加到递归调用的结果中。在这里,当 l
为奇数时,您将其加倍并停止,如果不是,您只需忘记列表的头部并将其余部分加倍(因为其余部分在逻辑上将是一个奇数列表)。