F# 将 CsvFile 转换为 Json object 数组
F# Convert CsvFile to Json object array
尝试学习 F# 并在尝试找到将 csv 文件转换为 json 数组的更好方法时卡住了,其中每一行 + header 是一个 json object 在那个数组中。
经过反复试验,我终于屈服了,采用了一种带有可变列表和映射的丑陋方法。有没有更好的方法可以实现?
let csvFileToJsonList (csvFile: FSharp.Data.CsvFile) =
let mutable tempList = List.empty<Map<string,string>>
let heads =
match csvFile.Headers with
| Some h -> h
| None -> [|"Missing"|] // what to do here?
let nbrOfColumns = csvFile.NumberOfColumns
for row in csvFile.Rows do
let columns = row.Columns
let mutable tempMap = Map.empty<string,string>
for i = 0 to nbrOfColumns-1 do
tempMap <- tempMap.Add(heads.[i], columns.[i])
tempList <- tempMap :: tempList
System.Text.Json.JsonSerializer.Serialize(tempList)
这将输出以下内容,这是目标:
[
{
"Header1": "Row1Val1",
"Header2": "Row1Val2",
"Header3": "Row1Val3",
"Header4": "Row1Val4",
"Header5": "Row1Val5"
},
{
"Header1": "Row2Val1",
"Header2": "Row2Val2",
"Header3": "Row2Val3",
"Header4": "Row2Val4",
"Header5": "Row2Val5"
}
]
这是我所能做到的最简单的,尽管更长的版本对您来说可能更具可读性:
let csvFileToJsonList (csvFile: FSharp.Data.CsvFile) =
let heads = csvFile.Headers |> Option.defaultValue [||]
csvFile.Rows
|> Seq.map (fun row -> Seq.zip heads row.Columns |> Map)
|> System.Text.Json.JsonSerializer.Serialize
这会按原始顺序生成输出,我认为这是更可取的(您的解决方案颠倒了顺序)。
这也假设一些 headers 存在,否则输出将为空 objects。
说明:对于每一行,使用 Seq.zip
生成一个 header-value 元组序列。将其传递给 Map
构造函数以创建地图,提供一系列可以序列化的地图。
请注意,使用 dict
而不是 Map
可能会更快一些。
您还可以使用 CsvProvider
创建类型对象(行)
open FSharp.Data
type Persons =
CsvProvider<"David,Raab,19.02.1983",
Schema="First (string), Last (string), BirthDay(string)",
HasHeaders=true>
let parseCsv (reader:System.IO.TextReader) = [
let data = Persons.Load reader
for row in data.Rows do
Map [
("First", row.First)
("Last", row.Last)
("Birthday", row.BirthDay)
]
]
返回地图列表而不是 Json,但我想您会知道如何将其更改为序列化数据。
尝试学习 F# 并在尝试找到将 csv 文件转换为 json 数组的更好方法时卡住了,其中每一行 + header 是一个 json object 在那个数组中。
经过反复试验,我终于屈服了,采用了一种带有可变列表和映射的丑陋方法。有没有更好的方法可以实现?
let csvFileToJsonList (csvFile: FSharp.Data.CsvFile) =
let mutable tempList = List.empty<Map<string,string>>
let heads =
match csvFile.Headers with
| Some h -> h
| None -> [|"Missing"|] // what to do here?
let nbrOfColumns = csvFile.NumberOfColumns
for row in csvFile.Rows do
let columns = row.Columns
let mutable tempMap = Map.empty<string,string>
for i = 0 to nbrOfColumns-1 do
tempMap <- tempMap.Add(heads.[i], columns.[i])
tempList <- tempMap :: tempList
System.Text.Json.JsonSerializer.Serialize(tempList)
这将输出以下内容,这是目标:
[
{
"Header1": "Row1Val1",
"Header2": "Row1Val2",
"Header3": "Row1Val3",
"Header4": "Row1Val4",
"Header5": "Row1Val5"
},
{
"Header1": "Row2Val1",
"Header2": "Row2Val2",
"Header3": "Row2Val3",
"Header4": "Row2Val4",
"Header5": "Row2Val5"
}
]
这是我所能做到的最简单的,尽管更长的版本对您来说可能更具可读性:
let csvFileToJsonList (csvFile: FSharp.Data.CsvFile) =
let heads = csvFile.Headers |> Option.defaultValue [||]
csvFile.Rows
|> Seq.map (fun row -> Seq.zip heads row.Columns |> Map)
|> System.Text.Json.JsonSerializer.Serialize
这会按原始顺序生成输出,我认为这是更可取的(您的解决方案颠倒了顺序)。
这也假设一些 headers 存在,否则输出将为空 objects。
说明:对于每一行,使用 Seq.zip
生成一个 header-value 元组序列。将其传递给 Map
构造函数以创建地图,提供一系列可以序列化的地图。
请注意,使用 dict
而不是 Map
可能会更快一些。
您还可以使用 CsvProvider
创建类型对象(行)
open FSharp.Data
type Persons =
CsvProvider<"David,Raab,19.02.1983",
Schema="First (string), Last (string), BirthDay(string)",
HasHeaders=true>
let parseCsv (reader:System.IO.TextReader) = [
let data = Persons.Load reader
for row in data.Rows do
Map [
("First", row.First)
("Last", row.Last)
("Birthday", row.BirthDay)
]
]
返回地图列表而不是 Json,但我想您会知道如何将其更改为序列化数据。