我正在尝试 F# 中的一些小任务来帮助掌握这门语言。
我想编写一个函数,它接受一个 n 维列表并返回一个包含每个维度的所有元素的一维列表。
例如,如果输入是以下 3 维列表:[[[1;2];[3;4]];[[5;6];[7;8]]],输出将是:[1;2;3;4;5;6;7;8]
对于 2 维 -> 1 维,函数非常简单:
let coalesce list= List.collect(fun item -> item) list
这是我尝试将其推广到 n 维:
let rec coalesce (list, dimension) =
if dimension = 1 then list
else coalesce (List.collect(fun item -> item) list, dimension - 1)
当我尝试编译时出现以下错误:
错误 FS0001:类型不匹配。期待一个
'列表列表
但给了一个
'一个列表
当统一 ''a' 和 ''a list' 时,结果类型将是无限的
问题在这里:
List.collect(fun item -> item) list
我的想法显然有问题。编写此类函数的正确方法是什么?
最佳答案
此操作类型不正确,但这里有一个适用于 IEnumerable
的示例s 并返回 list<obj>
:
let rec coalesce(list:System.Collections.IEnumerable, dim) =
[
if dim=1 then for x in list do yield x
else
for x in list do
match x with
| :? System.Collections.IEnumerable as s ->
yield! coalesce(s, dim-1)
| _ -> failwith "bad shape"
]
printfn "%A" (coalesce([1;2], 1))
printfn "%A" (coalesce([[1;2];[3;4]], 2))
printfn "%A" (coalesce([[[1;2];[3;4]];[[5;6];[7]]], 3))
你也可以这样写
let rec flatten(list:System.Collections.IEnumerable) =
[for x in list do
match x with
| :? System.Collections.IEnumerable as s -> yield! flatten(s)
| _ -> yield x
]
哪个更通用,例如
let weird : obj list = [[box [1;2]; box 3]; 4; [box [5;6]; box 7]]
printfn "%A" (flatten weird)
编辑
@Jon Harrop 提出了另一种策略——为嵌套列表创建一个新类型:
type NestedListElement<'T> = //'
| L of NestedListElement<'T> list //'
| V of 'T //'
let rec flatten nlist =
[for x in nlist do
match x with
| L l -> yield! flatten l
| V v -> yield v
]
let nested = [L[L[V 1;V 2]; V 3]; V 4; L[L[V 5;V 6]; V 7]]
printfn "%A" (flatten nested)
关于F#函数将n维列表转换为一维列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3207522/