我正在读取文件,我想在第一行做其他事情,在其他所有行做其他事情
let lines = System.IO.File.ReadLines "filename.txt" |> Seq.map (fun r -> r.Trim())
let head = Seq.head lines
let tail = Seq.tail lines
```
问题:由于tail
已关闭,因此对TextReader
的调用失败。
这意味着对Seq
进行两次评估:一次获取head
,一次获取tail
。
如何在保持Seq
且不重新评估Seq的情况下获得firstLine和lastLines?
签名可以是,例如:
let fn: ('a -> Seq<'a> -> b) -> Seq<'a> -> b
答案 0 :(得分:8)
最简单的操作可能只是使用Seq.cache
来包装lines
序列:
let lines =
System.IO.File.ReadLines "filename.txt"
|> Seq.map (fun r -> r.Trim())
|> Seq.cache
文档中的注释:
此结果序列将具有与输入序列相同的元素。结果可以被枚举多次。输入序列最多枚举一次,并且仅在必要时枚举。当重复评估原始序列中的项目在计算上很昂贵时,或者如果迭代序列会导致用户不希望重复多次的副作用,则缓存序列通常非常有用。
答案 1 :(得分:4)
我通常使用seq
表达式,其中Stream
的作用范围是表达式内部。这样一来,您就可以在处理流之前完全枚举序列。我通常使用这样的功能:
let readLines file =
seq {
use stream = File.OpenText file
while not stream.EndOfStream do
yield stream.ReadLine().Trim()
}
然后,您应该能够调用Seq.head
并获得失败的第一行,而Seq.last
可以获得文件的最后一行。我认为这将在技术上创建两个不同的枚举器。如果只想一次准确地读取文件,那么将序列具体化为列表或使用类似Seq.cache
的函数将是您的最佳选择。