我试图使一个函数返回每个子列表的第一个元素的列表,包括空列表被返回为[]。
let firstCol (lst: 'a list list) =
List.map List.head lst
只要没有空列表就可以工作,但是当我的输入包含空列表时,我得到以下错误消息:
System.ArgumentException: The input list was empty.
我该怎么做?提前谢谢。
您可以使用List.tryHead
或从地面编写自己的函数,或使用List.fold
/List.foldBack
等辅助程序。
如果你做List.tryHead
,你得到一个选项作为结果,Some
元素,或None
,如果列表是空的。所以你必须考虑None
的情况。不能为子列表返回空列表,因为列表必须具有相同的类型。但是你可以跳过空表。或者保留期权。当列表为空时,
let xs = [[1;2;3];[];[4;5;6];[];[7;8;9]]
printfn "%A" (List.map List.tryHead xs)
返回[Some 1; None; Some 4; None; Some 7]
你可以跳过空子列表
printfn "%A" (List.choose List.tryHead xs)
得到
[1;4;7]
或者自己做,使用List.foldBack
let firstCol xs =
let folder xs acc =
match List.tryHead xs with
| Some x -> x :: acc
| None -> acc
List.foldBack folder xs []
或者更基本的
let rec firstCol xs =
match xs with
| [] -> []
| []::xss -> firstCol xss
| (x::xs)::xss -> x :: firstCol (xss)
最后一个版本不是尾递归的,但无论如何,您应该尝试并训练以理解这种递归定义。并且能够自己将这样的函数转化为尾递归。
您要求的内容无法用您现有的签名完成。考虑以下输入:
[
[1; 2]
[]
[3; 4]
]
看起来您正在请求以下输出:
[
1
[]
3
]
但是,在f#中这不是一个合法的列表,因为它的元素没有相同的类型。
我认为你最好的选择是使用tryHead
代替,正如其他答案所建议的。