如何解码 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
我有一个 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