"left join" 在 F# 中的性能

Performance of "left join" in F#

我实际上是在尝试在 F# 中执行 sql 左连接,接收两个 csv 文件并生成第三个。我的文件并不大(大约 20 万行),但我仍然体验到可怕的性能 - 事实上,在 xl 中使用 vlookup 速度更快...

csv 都有一个标识符“列”,它包含兼容的值,但不能保证一个 csv 中存在的值在另一个 csv 中。

我修改过它,我怀疑通过一个 csv 搜索另一个 csv 中的每一行是杀手。

编辑:用 Map 替换 Array 可以大大提高性能。但我想这仍然可以进一步改进

有什么改进的想法吗?

一些(伪)代码:

open FSharp.Data

type DataLeft = 
    CsvProvider<Sample = "identifier;var1;var2", AssumeMissingValues = true, Schema = "identifier (string), var1, var2", Separators=";", HasHeaders=true, Encoding="UTF-8">

type DataRight = 
    CsvProvider<Sample = "identifier;var3;var4", AssumeMissingValues = true, Schema = "identifier (string), var3 (float option), var4 (float option)", Separators=";", HasHeaders=true, Encoding="UTF-8">

type Output =
    CsvProvider<Sample = "identifier;var1;var2;var3;var4", AssumeMissingValues = true, Schema = "identifier (string), var1, var2, var3 (float option), var4 (float option)", Separators=";", HasHeaders=true, Encoding="UTF-8">

let leftRows = DataLeft.Load(leftPath).Rows

// (slightly) more efficient to convert to array
let rightRows = DataRight.Load(rightPath).Rows |> Seq.toArray
**EDIT: let rightRows = DataRight.Load(rightPath).Rows |> Seq.map (fun row -> (row.Identifier, row)) |> Map.ofSeq**

let getMissingVars (row : DataLeft.Row) =
    let id = row.Identifier
    let rightRow = rightRows |> Array.tryFind (fun rRow -> rRow.Identifier = id)
**EDIT: let rightRow = rightRows.TryFind(id)**
    match rightRow with
    | None ->
        Output.Row(
            id,
            row.Var1,
            row.Var2,
            None,
            None)
    | Some realRow -> 
        Output.Row(
            id,
            row.Var1,
            row.Var2,
            realRow.Var3,
            realRow.Var4)

let rows = leftRows |> Seq.map getMissingVars

let csv = new Output(rows)
csv.Save(path = "outputPath")

简单地创建一个用于查找的字典就解决了这个问题。我放弃了进一步改进的尝试,因此将其发布为答案。

根据编辑替换

let rightRows = DataRight.Load(rightPath).Rows |> Seq.toArray

let rightRows = 
    DataRight.Load(rightPath).Rows 
    |> Seq.map (fun row -> (row.Identifier, row)) 
    |> Map.ofSeq

或一些更好的字典。然后将 Array.tryFind 替换为 Map.tryFind