"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
我实际上是在尝试在 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