F#:将一系列序列展平为单个Seq

时间:2012-03-19 17:47:45

标签: f# f#-scripting

我正在尝试构建一个包含多个文件内容的单个序列,以便对其进行排序然后传递给图形组件。但是我一直试图将每个文件的内容折叠在一起。下面的伪代码不会编译,但希望能显示我想要实现的目的。

任何帮助,非常感谢。

open System.IO 

let FileEnumerator filename = seq { 
        use sr = System.IO.File.OpenText(filename)
           while not sr.EndOfStream do 
           let line = sr.ReadLine()
            yield line 
}

let files = Directory.EnumerateFiles(@"D:\test_Data\","*.csv",SearchOption.AllDirectories)

let res =
   files 
        |> Seq.fold(fun x item -> 
        let lines =  FileEnumerator(item)
        let sq = Seq.concat x ; lines
        sq
    ) seq<string>

printfn "%A" res

2 个答案:

答案 0 :(得分:12)

您实际上是在尝试重新实现Files.Readlines,它将文件内容返回为seq<string>。然后可以将其与Seq.concat连接:

let res = Directory.EnumerateFiles(@"D:\test_Data","*.csv",SearchOption.AllDirectories)
          |> Seq.map File.ReadLines 
          |> Seq.concat

答案 1 :(得分:4)

要解决原始方法中的问题,您需要使用Seq.append代替Seq.concatfold的初始值应为空序列,可以写为Seq.empty

let res = 
   files |> Seq.fold(fun x item ->  
        let lines =  FileEnumerator(item) 
        let sq = Seq.append x lines 
        sq ) Seq.empty

如果您想使用Seq.concat,则必须编写Seq.concat [x; lines],因为concat需要连接一系列序列。另一方面,append只需要两个序列,因此在这里使用起来更容易。

连接所有行的另一种(更简单的)方法是在序列表达式中使用yield!

let res = 
  seq { for item in files do
          yield! FileEnumerator(item) }

这将通过迭代所有文件并将文件中的所有行(按顺序)添加到结果序列来创建序列。 yield!构造将序列的所有元素添加到结果中。