如何在Swift中解码pandas DataFrame导出的split格式JSON数据
解决方法
核心思路
你之前的解码逻辑错误在于:pandas split格式的data字段存储的是按行排列的数组集合,并不是Product结构体的键值对结构,所以无法直接声明为[[Product]]类型解码。
要避免硬编码列顺序,只需要先从返回的columns字段中提前映射每个Product属性对应的列索引,再逐行读取构造对象即可。
具体实现步骤
1. 定义基础工具类型
首先实现一个可兼容Int、String等基础JSON类型的通用解码类型AnyCodable,用于解析data字段中混合类型的数组元素:
struct AnyCodable: Codable { let value: Any init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() if let intVal = try? container.decode(Int.self) { value = intVal } else if let stringVal = try? container.decode(String.self) { value = stringVal } else { throw DecodingError.dataCorruptedError(in: container, debugDescription: "不支持的类型") } } }
2. 定义pandas split格式中间解码结构
用于先把外层的列信息和原始数据解析出来:
struct PandasSplitRawResponse: Codable { let columns: [String] let data: [[AnyCodable]] // index字段用不到可以直接忽略 enum CodingKeys: String, CodingKey { case columns, data } }
3. 实现解码转换逻辑
解码完成后先构建字段到索引的映射,再逐行构造Product数组:
func decodeProductFromPandasJSON(data: Data) throws -> [Product] { // 先解码原始split结构 let rawResponse = try JSONDecoder().decode(PandasSplitRawResponse.self, from: data) // 提前映射每个Product属性对应的列索引,避免硬编码顺序 guard let cprcodeIdx = rawResponse.columns.firstIndex(of: "cprcode"), let iprcodeIdx = rawResponse.columns.firstIndex(of: "iprcode"), let psqtyIdx = rawResponse.columns.firstIndex(of: "psqty") else { throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: [], debugDescription: "缺少必要的列字段")) } // 逐行构造Product对象 var products = [Product]() for row in rawResponse.data { guard let cprcode = row[cprcodeIdx].value as? Int, let iprcode = row[iprcodeIdx].value as? String, let psqty = row[psqtyIdx].value as? Int else { throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: [], debugDescription: "行数据类型不匹配")) } products.append(Product(cprcode: cprcode, iprcode: iprcode, psqty: psqty)) } return products }
调用示例
直接传入接口返回的JSON数据即可得到[Product]结果:
// jsonData是从接口获取到的JSON数据 do { let products = try decodeProductFromPandasJSON(data: jsonData) print(products) // 得到最终需要的Product数组 } catch { print("解码失败: \(error)") }
内容的提问来源于stack exchange,提问作者Nic Wanavit
相关产品推荐
相关产品推荐

