1

我开始学习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())
4

3 回答 3

5

你的翻译在我看来不错。在 C# 中使用扩展方法(例如foo.Select(...))大致相当于使用管道和 F# 函数 from或模块List,具体取决于您使用的集合类型(例如)。SeqArrayfoo |> 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)
于 2013-01-09T14:10:07.473 回答
3

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

  • mutable在 F# 中List被命名为ResizeArray,它们作为内置集合(包括 Array、List、Seq)没有很好的支持。
  • 您通常不需要在 F# 中使用 LINQ,Array、List 和 Seq 模块绰绰有余。
  • 点 (.) 语法不能很好地与管道运算符配合使用。

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

let split (delim: string) (str: string) =
    str.Split([|delim|], StringSplitOptions.RemoveEmptyEntries)

let parse (csvData: string) = 
    csvData
    |> split Environment.NewLine
    |> Array.map (split ",")
于 2013-01-09T14:11:40.363 回答
1

此页面上的各种解决方案之间存在细微差别。例如,您的 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 ]
于 2013-01-09T15:37:19.683 回答