如何将文件读入F#中的seq行

Yin*_*Zhu 53 f#

这是C#版本:

public static IEnumerable<string> ReadLinesEnumerable(string path) {
  using ( var reader = new StreamReader(path) ) {
    var line = reader.ReadLine();
    while ( line != null ) {
      yield return line;
      line = reader.ReadLine();
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

但直接翻译需要一个可变的变量.

Joe*_*ler 88

如果您使用的是.NET 4.0,则可以使用File.ReadLines.

> let readLines filePath = System.IO.File.ReadLines(filePath);;

val readLines : string -> seq<string>
Run Code Online (Sandbox Code Playgroud)

  • "ReadLines和ReadAllLines方法的不同之处如下:当您使用ReadLines时,您可以在返回整个集合之前开始枚举字符串集合;当您使用ReadAllLines时,必须等待返回整个字符串数组才能访问因此,当您使用非常大的文件时,ReadLines可以更高效." (17认同)

Cha*_*ion 64

let readLines (filePath:string) = seq {
    use sr = new StreamReader (filePath)
    while not sr.EndOfStream do
        yield sr.ReadLine ()
}
Run Code Online (Sandbox Code Playgroud)


Tom*_*cek 18

回答是否存在用于封装此模式的库函数的问题 - 没有完全针对此的函数,但是有一个函数允许您从某个状态调用生成序列Seq.unfold.您可以使用它来实现上面的功能,如下所示:

new StreamReader(filePath) |> Seq.unfold (fun sr -> 
  match sr.ReadLine() with
  | null -> sr.Dispose(); None 
  | str -> Some(str, sr))
Run Code Online (Sandbox Code Playgroud)

sr值表示流读取器,并作为状态传递.只要它为您提供非空值,您就可以返回Some包含要生成的元素和状态(如果需要,可以更改).当它读取时null,我们处理它并返回None结束序列.这不是直接的等价物,因为它StreamReader在抛出异常时没有正确处理.

在这种情况下,我肯定会使用序列表达式(在大多数情况下它更优雅,更可读),但知道它也可以使用更高阶函数编写是有用的.


mar*_*ria 12

    let lines = File.ReadLines(path)                

    // To check
    lines |> Seq.iter(fun x -> printfn  "%s" x) 
Run Code Online (Sandbox Code Playgroud)


Lar*_*ann 5

在.NET 2/3上,您可以:

let readLines filePath = File.ReadAllLines(filePath) |> Seq.cast<string>
Run Code Online (Sandbox Code Playgroud)

在.NET 4上:

let readLines filePath = File.ReadLines(filePath);;
Run Code Online (Sandbox Code Playgroud)