recursion - 在 F# 中为两个列表定义 zip 函数
问题描述
遇到问题:
定义一个名为 zip 的函数,它将一对(元组)长度相等的列表作为单个参数并返回一个对列表。第一对应该包含每个列表的第一个元素,第二对包含每个列表的第二个元素,依此类推。
我被困住了,正在寻找关于我是否朝着正确的方向前进或应该尝试另一种方法的建议。
它必须是没有任何嵌套函数的单个函数定义,并且不能使用内置函数!
我所做的是:
let rec zip (a , b) =
if List.length a = 1 then List.head a , List.head b
else zip (List.tail a , List.tail b)
什么时候
> zip (["a"; "b"; "c"; "d"; "e"], [1; 2; 3; 4; 5]);;
被输入
val it : string * int = ("e", 5)
被退回。预期的结果应该是
val it : (string * int) list = [("a", 1); ("b", 2); ("c", 3); ("d", 4); ("e", 5)]
解决方案
让我们从您的原始实现开始:
let rec zip (a , b) =
if List.length a = 1 then List.head a , List.head b
else zip (List.tail a , List.tail b)
首先,类型是错误的——这会返回一个值的元组,而不是一个元组列表。它的作用是遍历列表(使用 跟随尾部List.tail
),当它到达末尾时,它返回每个列表的唯一元素,即"e"
and 5
。
解决此问题的第一步可能是添加类型注释。then
这将迫使您在分支中返回一个列表。如果你有两个单例列表["e"]
和[5]
,你想返回["e", 5]
:
let rec zip (a:'a list , b:'b list) : list<'a * 'b> =
if List.length a = 1 then [List.head a , List.head b]
else zip (List.tail a , List.tail b)
这仍然不对 - 在这种else
情况下,您只是在看尾巴,而忽略了头。您需要访问head
并将其连接到递归调用返回的列表:
let rec zip (a:'a list , b:'b list) : list<'a * 'b> =
if List.length a = 1 then [List.head a , List.head b]
else (List.head a, List.head b) :: zip (List.tail a , List.tail b)
这可行,但if .. then .. else
在这种情况下使用是不雅的。Filipe 的回答展示了如何通过模式匹配更好地做到这一点。
推荐阅读
- javascript - youtube api除了片段之外的任何参数都不起作用
- c# - 如何正确复制派生类中的字段?
- android - 对于布局文件
- git - 如何在同一 CLI 终端中在屏幕上显示“git branch”的输出?
- linux - 我 grep JSON 的一部分,但是当我对字符串使用输入文件时,它不起作用
- php - 如何使用 Flickr API 上传照片?
- multithreading - Spark-ML 中的交叉验证失败
- git - 在本地分支上工作后使用 git rebase
- google-cloud-platform - 如何使用 API 在 GCP 数据流中检索当前工作人员计数
- javascript - Mocha Chai AssertionError:预期数组是 json