es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo decodificar un JSON volcado por un Pandas Dataframe en Swift.

Tengo datos en formato JSON que son devueltos por una API REST en la forma de:

'split': dict como {'index' -> [index], 'columns' ->

, 'data' -> [values]}

esto se genera utilizando pandas.to_json(orient='split') en Python.

Me gustaría decodificar esto en un objeto Swift. Intenté usar Decodable, pero no puedo descubrir cómo asignar dinámicamente la posición de la columna al objeto.

Datos de ejemplo:

json
{
   "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],
      ]
}

Me gustaría que la salida fuera en forma de [Producto], donde

swift
struct Producto{
  let cprcode: Int
  let iprcode: String
  let psqty: Int
}

He intentado decodificar con una clase de arreglo personalizado como este, pero no estoy seguro de cómo dividirlos en objetos de productos. Ten en cuenta que las columnas son dinámicas, por lo que codificar el orden de las columnas en los datos es arriesgado.

swift
class ProductoDF: Codable {
    let columns: [String]
    let index: [Int]
    let data: [[Producto]]
}
Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Para asignar dinámicamente la posición de la columna al objeto Product, puedes utilizar un enfoque de clave dinámica en la enumeración CodingKeys de Swift. Así es como puedes decodificar los datos de ejemplo en una matriz de objetos Product:

    struct Product: Decodable {
        let cprcode: Int
        let iprcode: String
        let psqty: Int
    
        enum CodingKeys: String, CodingKey {
            case cprcode
            case iprcode
            case psqty
        }
    
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
    
            // Asignar dinámicamente las posiciones de las columnas a las propiedades correspondientes
            cprcode = try container.decode(Int.self, forKey: .init(stringValue: container.allKeys[0].stringValue)!)
            iprcode = try container.decode(String.self, forKey: .init(stringValue: container.allKeys[1].stringValue)!)
            psqty = try container.decode(Int.self, forKey: .init(stringValue: container.allKeys[2].stringValue)!)
        }
    }
    
    let jsonData = """
    {
        "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]
            ]
    }
    """.data(using: .utf8)!
    
    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .convertFromSnakeCase
    let productDF = try decoder.decode([String: [String: [Any]]].self, from: jsonData)
    let products = productDF["data"]!.map { Product(cprcode: $0[0] as! Int, iprcode: $0[1] as! String, psqty: $0[2] as! Int) }
    print(products)
    // Salida: [Product(cprcode: 123, iprcode: "abc", psqty: 123), Product(cprcode: 424, iprcode: "ads", psqty: 145), Product(cprcode: 63, iprcode: "hrw", psqty: 475), Product(cprcode: 8685, iprcode: "gds", psqty: 848), Product(cprcode: 754, iprcode: "ah", psqty: 659), Product(cprcode: 374, iprcode: "rh", psqty: 597)]
    

    En el ejemplo anterior, definimos la enumeración CodingKeys con claves dinámicas que se extraen de la propiedad allKeys del contenedor. Luego, utilizamos estas claves para obtener los valores JSON del contenedor y asignarlos a las respectivas propiedades de Product. Finalmente, decodificamos la cadena JSON utilizando la estrategia de decodificación de claves establecida en .convertFromSnakeCase para convertir automáticamente las claves JSON a propiedades Swift correspondientes.

Comments are closed.