空列表的头部



我试图使一个函数返回每个子列表的第一个元素的列表,包括空列表被返回为[]。

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代替,正如其他答案所建议的。

最新更新