F# pipelines and LINQ



我开始学f#了。我发现很难改变我对OO编程的看法。我想知道f#开发人员如何编写以下内容:

"传统"c#

public List<List<string>> Parse(string csvData){
    var matrix = new List<List<string>>();
    foreach(var line in csvData.Split(Environment.NewLine.ToArray(), StringSplitOptions.None)){
        var currentLine = new List<string>();
        foreach(var cell in line.Split(','){
            currentLine.Add(cell);
        }
        matrix.Add(currentLine);
    }
    return matrix;
}

"功能性"c#

public List<List<string>> Parse(string csvData){
    return csvData.Split(Environment.NewLine.ToArray(), StringSplitOptions.None).Select(x => x.Split(',').ToList()).ToList();
}
问题是:下面的代码是正确的吗? f#

let Parse(csvData:string) = 
    csvData.Split(Environment.NewLine.ToArray(), StringSplitOptions.None).ToList()
    |> Seq.map(fun x -> x.Split(',').ToList())

我看你的翻译不错。在c#中使用扩展方法(例如foo.Select(...))大致相当于在List, SeqArray模块中使用管道和f#函数,具体取决于您使用的集合类型(例如foo |> Seq.map (...))。

使用来自f#的LINQ扩展方法并将它们与f#结构混合使用是完全可以的,但我只会在没有相应的f#函数时这样做,因此我可能会避免示例中的ToArray()ToList()并编写:

open System
let Parse(csvData:string) = 
    // You can pass the result of `Split` (an array) directly to `Seq.map`
    csvData.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.None)
    // If you do not want to get sequence of arrays (but a sequence of F# lists)
    // you can convert the result using `Seq.toList`, but I think working with
    // arrays will be actually easier when processing CSV data
    |> Seq.map(fun x -> x.Split(',') |> Seq.toList)

在您的解决方案中有一些东西不是很f#:

  • 可变List在f#中被命名为ResizeArray,它们没有很好的支持作为内置集合,包括Array, List, Seq。
  • 你不需要经常在f#中使用LINQ, Array, List和Seq模块绰绰有余。
  • dot(.)语法不能很好地处理管道操作符。

将返回类型更改为string [] [],您可以使用辅助函数编写更简洁的代码:

let split (delim: string) (str: string) =
    str.Split([|delim|], StringSplitOptions.RemoveEmptyEntries)
let parse (csvData: string) = 
    csvData
    |> split Environment.NewLine
    |> Array.map (split ",")

本页上的各种解决方案之间存在细微差异。例如,你的c#解决方案和pad的解决方案是渴望的,但你的f#版本和Tomas的是懒惰的。你的和pad在Environment.NewLine上分裂,但Tomas在NewLine中的任何字符上分裂(我猜你想要后者,因为你调用了接受StringSplitOptions的过载)。也许这些很重要;也许不是。

无论如何,这里有一个不同的pad的解决方案。

let split (delims: char[]) (str: string) =
  str.Split(delims, StringSplitOptions.RemoveEmptyEntries)
let parse csvData =
  let nl = Environment.NewLine.ToCharArray()
  [ for x in split nl csvData -> split [|','|] x ]

相关内容

  • 没有找到相关文章

最新更新