Swift中如何从JSON解析的Dimensions字典提取字符串数组?
问题与解决方案
需求
解析包含Dimensions(字典数组)和Measures(字符串数组)的JSON,已编写对应Codable模型,解析完成后需将Dimensions中的所有键提取为与Measures格式一致的字符串数组。
原始JSON
{"Dimensions":[{"Channel":"VARCHAR"},{"Indication":"VARCHAR"},{"LOT":"VARCHAR"},{"Monthly":"DATE"},{"Yearly":"VARCHAR"},{"Quarterly":"DATE"},{"Parameter_Classification":"VARCHAR"},{"Parameter_Type_1":"VARCHAR"},{"Parameter_Type_2":"VARCHAR"},{"Parameter_Type_3":"VARCHAR"},{"Payer_Type":"VARCHAR"},{"Product":"VARCHAR"},{"Project_Name":"VARCHAR"},{"Regime":"VARCHAR"},{"Region":"VARCHAR"},{"Scenario":"VARCHAR"},{"Trial_Name":"VARCHAR"}],"Measures":["ANSP","ASP","Demand units","DOH","EPI","Ex Factory","Gross sales","Inventory Units","Market Share","Net sales","NPS PAP","Patients","Revenue","TRx","Units","WAC"]}
已实现的Codable模型
struct Welcome: Codable { let dimensions: [Dimension] let measures: [String] enum CodingKeys: String, CodingKey { case dimensions = "Dimensions" case measures = "Measures" } } struct Dimension: Codable { let channel, indication, lot, monthly: String? let yearly, quarterly, parameterClassification, parameterType1: String? let parameterType2, parameterType3, payerType, product: String? let projectName, regime, region, scenario: String? let trialName: String? enum CodingKeys: String, CodingKey { case channel = "Channel" case indication = "Indication" case lot = "LOT" case monthly = "Monthly" case yearly = "Yearly" case quarterly = "Quarterly" case parameterClassification = "Parameter_Classification" case parameterType1 = "Parameter_Type_1" case parameterType2 = "Parameter_Type_2" case parameterType3 = "Parameter_Type_3" case payerType = "Payer_Type" case product = "Product" case projectName = "Project_Name" case regime = "Regime" case region = "Region" case scenario = "Scenario" case trialName = "Trial_Name" } }
现有解析方法
private func decodeJson(welcomeString: String) { let data = Data(welcomeString.utf8) do { let infoType = try JSONDecoder().decode(Welcome.self, from: data) // print(infoType.dimensions) // print(infoType.measures) } catch let error { print(error) } }
解决方案
方法一:利用模型CodingKeys提取(推荐)
由于Dimension的CodingKeys已映射JSON中所有可能的键名,只需给CodingKeys添加CaseIterable协议,即可直接提取所有键的原始名称:
- 修改
Dimension.CodingKeys,添加CaseIterable协议:
enum CodingKeys: String, CodingKey, CaseIterable { case channel = "Channel" case indication = "Indication" case lot = "LOT" case monthly = "Monthly" case yearly = "Yearly" case quarterly = "Quarterly" case parameterClassification = "Parameter_Classification" case parameterType1 = "Parameter_Type_1" case parameterType2 = "Parameter_Type_2" case parameterType3 = "Parameter_Type_3" case payerType = "Payer_Type" case product = "Product" case projectName = "Project_Name" case regime = "Regime" case region = "Region" case scenario = "Scenario" case trialName = "Trial_Name" }
- 修改解析方法,提取键数组:
private func decodeJson(welcomeString: String) { let data = Data(welcomeString.utf8) do { let infoType = try JSONDecoder().decode(Welcome.self, from: data) // 提取Dimensions的所有键名,格式与Measures一致 let dimensionKeys = Dimension.CodingKeys.allCases.map { $0.rawValue } print(dimensionKeys) print(infoType.measures) } catch let error { print(error) } }
方法二:直接解析原始JSON(兼容模型未覆盖的键)
如果担心JSON中存在模型未定义的键,可直接解析原始JSON数据提取键:
private func decodeJson(welcomeString: String) { let data = Data(welcomeString.utf8) do { // 解析为原始JSON对象 guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any], let dimensions = json["Dimensions"] as? [[String: Any]] else { return } // 提取所有键并去重 let dimensionKeys = dimensions.flatMap { $0.keys }.unique() print(dimensionKeys) // 同时解析模型获取Measures if let infoType = try? JSONDecoder().decode(Welcome.self, from: data) { print(infoType.measures) } } catch let error { print(error) } } // 给数组添加去重扩展 extension Array where Element: Hashable { func unique() -> [Element] { var seen = Set<Element>() return filter { seen.insert($0).inserted } } }
内容的提问来源于stack exchange,提问作者nitpaxy
相关产品推荐
相关产品推荐

