简体   繁体   中英

Decode JSON object to Swift Dictionary keeping keys

Using this code:

import Foundation

let jsonData = """
{
  "equipment": [
    {
      "name": "BigBox",
      "origin": "Customer",
      "type_codes": [
        "XCD",
        "QPR"
      ],
      "category": "Shipping",
      "product_counts": {
        "M": 1,
        "D": 2,
        "W": 1,
        "F": 1
      }
    },
    {
      "name": "LittleBox",
      "origin": "Manufacturer",
      "type_codes": [
        "XCD",
        "DDP"
      ],
      "category": "Storage",
      "product_counts": {
        "W": 3,
        "F": 2
      }
    }
  ]
}
""".data(using: .utf8)!

struct EquipmentListing: Codable {
    let equipment: [Equipment]

    enum CodingKeys: String, CodingKey {
        case equipment
    }
}

struct Equipment: Codable {
    let name: String
    let origin: String
    let typeCodes: [String]
    let category: String
    let productCounts: ProductCounts

    enum CodingKeys: String, CodingKey {
        case name
        case origin
        case typeCodes = "type_codes"
        case category
        case productCounts = "product_counts"
    }
}

struct ProductCounts: Codable {
    let m: Int?
    let d: Int?
    let w: Int?
    let f: Int?

    enum CodingKeys: String, CodingKey {
        case m = "M"
        case d = "D"
        case w = "W"
        case f = "F"
    }
}

let equipmentListing = try! JSONDecoder().decode(EquipmentListing.self, from: jsonData)
print( equipmentListing.equipment[0].productCounts.d )

This works, but has the drawback that the productCounts keyed object is turned into a struct with hardcoded members but there could be dozens of possibilities there and I don't want to have to list them all in the code as Optionals. I want to be able to decode my source JSON so that productCounts comes out as a Dictionary instead of a struct.

Basically, I would like the last line to be this instead:

print( equipmentListing.equipment[0].productCounts["D"] )

** Bonus points if it's possible to change the keys in productCounts from, eg, D to Dishwasher , M to Microwave , etc. as the source is decoded so that this possible:

print( equipmentListing.equipment[0].productCounts["Dishwasher"] )

Since you want to map from an arbitrary string to an integer, that's a Dictionary, just as you suggest. You can get rid of the ProductCounts struct and use [String: Int] .

struct Equipment: Codable {
    let name: String
    let origin: String
    let typeCodes: [String]
    let category: String
    let productCounts: [String: Int]  // <===

    enum CodingKeys: String, CodingKey {
        case name
        case origin
        case typeCodes = "type_codes"
        case category
        case productCounts = "product_counts"
    }
}

print( equipmentListing.equipment[0].productCounts["D"] )
// Optional(2)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM