看看这两个线程之后:F#是否与Haskell相同?,从F#中的N个不同索引的序列中取N个元素 ,我一直想知道在列表上使用序列运算符的最佳方法,甚至是使用它们.
我现在是F#的新手,我正在编写一个程序,它必须处理从HtmlAgilityPack获得的大量序列.在Seq模块中有一些有趣的运算符,但正如那些线程所述,它可能与性能有关,如果我们不得不在seq - > list之间不断转换,它也会使代码混乱,而不是解决问题的东西.这就是我开始学习F#的原因.
一个简单的例子是当我需要取一个列表的'N'个元素时:
listOfRows
|> Seq.take 2
// Now I don't have a list anymore, it returns a sequence
|> List.ofSeq
Run Code Online (Sandbox Code Playgroud)
那么,任何人都可以了解处理这些情景的最佳方法吗?我可以使用Seq.take和Seq.skip来处理解决方案,但这已知效率非常低.另一方面,将功能内置到标准库中并且必须重新实现它以在不同集合上使用相同的概念,或者通过显式转换使代码更脏,这是一种耻辱.
我怎么能看到'list - > seq'和'seq - > list'之间每次转换对性能的影响?
非常感谢.
这些实现起来相当简单.
module List =
let take n items =
let rec take' acc = function
| 0, _ -> List.rev acc
| _, [] -> invalidOp "count exceeds number of elements"
| n, h::t -> take' (h::acc) (n-1, t)
take' [] (n, items)
let rec skip n items =
match n, items with
| 0, _ -> items
| _, [] -> invalidOp "count exceeds number of elements"
| n, _::t -> skip (n-1) t
Run Code Online (Sandbox Code Playgroud)
这是他们与Seq同行相比的表现.
let n = 10000000
let l = List.init n id
let test f = f (n-1) l
test List.take //Real: 00:00:03.724, CPU: 00:00:03.822, GC gen0: 57, gen1: 34, gen2: 1
test Seq.take |> Seq.toList //Real: 00:00:04.953, CPU: 00:00:04.898, GC gen0: 57, gen1: 33, gen2: 0
test List.skip //Real: 00:00:00.044, CPU: 00:00:00.046, GC gen0: 0, gen1: 0, gen2: 0
test Seq.skip |> Seq.toList //Real: 00:00:01.147, CPU: 00:00:01.154, GC gen0: 0, gen1: 0, gen2: 0
Run Code Online (Sandbox Code Playgroud)
如果毫秒计算您的应用程序,那么创建"缺失" List函数可能是值得的.否则,我会说使用Seq版本完全没问题.