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,但我想您会知道如何将其更改为序列化数据。