【问题标题】:F# Convert CsvFile to Json object arrayF# 将 CsvFile 转换为 Json 对象数组
【发布时间】:2021-10-29 09:47:09
【问题描述】:

尝试学习 F#,但在尝试找到将 csv 文件转换为 json 数组的更好方法时遇到了困难,其中每一行 + 标题都是该数组中的一个 json 对象。

经过反复试验,我终于屈服并采用可变列表和映射的丑陋方法。有没有更好的方法可以实现?

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"
        }
    ]

【问题讨论】:

    标签: f# f#-data


    【解决方案1】:

    这是我可以做到的最简单的,虽然更长的版本可能对你来说更易读:

    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
    

    这会以原始顺序产生输出,我认为这是更可取的(您的解决方案颠倒了顺序)。

    这也假设存在一些标头,否则输出将为空对象。

    描述:对于每一行,使用Seq.zip 来生成一个标题值元组序列。将其传递给Map 构造函数以创建地图,提供一系列地图,可以序列化。

    请注意,使用dict 而不是Map 可能会快一些。

    【讨论】:

    • 哇,我认为有一个好看的解决方案,但从来没有这么简单。感谢您回答并教我这个!
    【解决方案2】:

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

    【讨论】:

    • 我实际上已经对此进行了测试,并且一开始很喜欢它,但是当示例标题可能发生变化时变得更加困难,因此需要寻找一种更动态的方法。我喜欢你构造 parseCsv 函数的方式,所以可能会测试类似的东西。谢谢@david!
    猜你喜欢
    • 2012-07-21
    • 2020-10-02
    • 1970-01-01
    • 1970-01-01
    • 2018-09-12
    • 2015-10-30
    • 1970-01-01
    相关资源
    最近更新 更多