如何解码 swift 中由 pandas 数据帧转储的 json

How to decode a json dumped by pandas dataframe in swift

我有一个 json 数据,由 api 以

的形式返回

‘split’ : dict like {‘index’ -> [index], ‘columns’ -> [columns], ‘data’ -> [values]} 这是使用 Python

中的 pandas.to_json(orient=‘split’) 生成的

我想将其解码为 swift 对象。我尝试使用 decodable 但我无法弄清楚如何将列位置动态分配给对象

示例数据:

{
"columns":
   ["cprcode","iprcode","psqty"],
"index":
   [0,3,4,5,6,11],
"data":
   [
     [123,"abc",123],
     [424, "ads",145],
     [63, "hrw",475],
     [8685, "gds",848],
     [754, "ah",659],
     [374, "rh",597],
   ]
}

我希望输出在 [Product] 的 for 中 其中

struct Product{
  let cprcode: Int
  let iprcode: String
  let psqty: Int
}

我试过了

像这样使用自定义数组 class 解码,但我不确定如何将它们拆分为产品对象。请注意,列是动态的,因此对数据中列的顺序进行硬编码是有风险的。

class ProductDF:Codable{
    let columns:[String]
    let index:[Int]
    let data:[[Product]]
}

这可以通过自定义 init(from:) 来完成,我们使用嵌套容器从“数据”中提取产品对象。

由于“数据”下的每个子数组都是一个产品,我们稍微更改了声明

struct ProductDF: Codable {
    let columns: [String]
    let index: [Int]
    let data: [Product]
}

为了稍微简化代码,我们为列创建了一个枚举

enum DataColumn: String {
    case cprcode, iprcode, psqty
}

然后是我们添加到 ProductDF

init(from:)
init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    columns = try container.decode([String].self, forKey: .columns)
    index = try container.decode([Int].self, forKey: .index)

    var dataContainer = try container.nestedUnkeyedContainer(forKey: .data)
    var products = [Product]()
    while !dataContainer.isAtEnd {
        var array = try dataContainer.nestedUnkeyedContainer()
        var cprCode = 0
        var iprCode = ""
        var psQty = 0
        for column in columns {
            switch DataColumn(rawValue: column) {
            case .cprcode:
                cprCode = try array.decode(Int.self)
            case .iprcode:
                iprCode = try array.decode(String.self)
            case .psqty:
                psQty = try array.decode(Int.self)
            case .none:
                fatalError()
            }
        }
        let product = Product(cprcode: cprCode, iprcode: iprCode, psqty: psQty)
        products.append(product)
    }
    data = products
}

这应该完成基本工作,尽管我建议通过抛出错误而不是使用 fatalError 来改进错误处理,并检查是否已将某些内容分配给 while 循环内的所有 3 个变量,例如通过将它们设为可选并在创建 Product

之前验证它们都不是 nil