在F#中从列表中实现类似于切片的功能

18

使用数组let foo = [|1;2;3;4|],我可以使用以下任何一种方法从数组中返回一个片段。

foo.[..2] 
foo.[1..2] 
foo.[2..]

如何对列表List let foo2 = [1;2;3;4] 进行同样的操作?当我尝试使用相同的语法时,我会得到 error FS00039: The field, constructor or member 'GetSlice' is not defined.

获取列表的子集的首选方法是什么,为什么它们不支持 GetSlice?

2个回答

44

如何获取列表的子集?为什么不支持GetSlice方法?

让我们先回答最后一个问题,再回答第一个问题:

为什么列表不支持GetSlice方法?

列表实现为链表,因此我们不能高效地通过索引访问它们。相对而言,foo.[|m..n|] 对于数组来说需要 O(n-m) 的时间,而等效的语法在列表上需要 O(n)的时间。这是一个非常重要的问题,因为它防止我们在大多数情况下有效地使用切片语法。

例如,我们可以在线性时间内将数组分割成大小相等的片段:

let foo = [|1 .. 100|]
let size = 4
let fuz = [|for a in 0 .. size .. 100 do yield foo.[a..a+size] |]

但如果我们使用列表呢?每次调用 foo.[a..a+size] 的时间会越来越长,整个操作的时间复杂度是 O(n^2),这使得它非常不适合该任务。

大多数情况下,切片一个列表是错误的方法。我们通常使用模式匹配来遍历和操作列表。

切片列表的首选方法?

尽可能使用模式匹配。否则,您可以使用 Seq.skipSeq.take 来为您分割列表和序列:

> [1 .. 10] |> Seq.skip 3 |> Seq.take 5 |> Seq.toList;;
val it : int list = [4; 5; 6; 7; 8]

10

F# 4.0将允许对列表使用切片语法(链接)。

这里提供了一个解释(链接):

F#列表类型已经支持索引运算符 xs.[3]。尽管在F#中,列表是链接列表,但由于列表在F#中非常常用,因此在F# 2.0中决定支持此功能。

既然支持索引语法,也应该支持F#切片语法,例如 xs.[3..5]。必须切换到数组类型才能使用切片非常奇怪,但对于索引操作则不需要进行这种转换。

但朱丽叶的回答仍然正确,即大多数情况下,对列表进行切片是错误的方法,因此在使用此功能时要明智。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接