我将此作为 API 的响应
{
"AAPL": {
"quote": {
"symbol": "AAPL",
"companyName": "Apple Inc.",
"sector": "Technology"
}
},
"FB": {
"quote": {
"symbol": "FB",
"companyName": "Facebook Inc.",
"sector": "Technology"
}
}
*... lots of stocks*
}
如何将其转换为这个? (稍后解码)
[
{
"symbol": "AAPL",
"companyName": "Apple Inc.",
"sector": "Technology"
},
{
"symbol": "FB",
"companyName": "Facebook Inc.",
"sector": "Technology"
}
*... lots of stocks*
]
不只是AAPL或FB,我需要大量“记录”的最佳答案
所以问题实际上不是改变结构而是解码 json。我认为最好的方法是将其变成标准形式。但我错了。我发现了一篇名为“Decode and Flatten JSON with Dynamic Keys using Decodable”的文章。这解决了我的问题!
{
"S001": {
"firstName": "Tony",
"lastName": "Stark"
},
"S002": {
"firstName": "Peter",
"lastName": "Parker"
},
"S003": {
"firstName": "Bruce",
"lastName": "Wayne"
}
}
struct DecodedArray: Decodable {
var array: [Student]
// Define DynamicCodingKeys type needed for creating
// decoding container from JSONDecoder
private struct DynamicCodingKeys: CodingKey {
// Use for string-keyed dictionary
var stringValue: String
init?(stringValue: String) {
self.stringValue = stringValue
}
// Use for integer-keyed dictionary
var intValue: Int?
init?(intValue: Int) {
// We are not using this, thus just return nil
return nil
}
}
init(from decoder: Decoder) throws {
// 1
// Create a decoding container using DynamicCodingKeys
// The container will contain all the JSON first level key
let container = try decoder.container(keyedBy: DynamicCodingKeys.self)
var tempArray = [Student]()
// 2
// Loop through each key (student ID) in container
for key in container.allKeys {
// Decode Student using key & keep decoded Student object in tempArray
let decodedObject = try container.decode(Student.self, forKey: DynamicCodingKeys(stringValue: key.stringValue)!)
tempArray.append(decodedObject)
}
// 3
// Finish decoding all Student objects. Thus assign tempArray to array.
array = tempArray
}
}
struct Student: Decodable {
let firstName: String
let lastName: String
// 1
// Define student ID
let studentId: String
// 2
// Define coding key for decoding use
enum CodingKeys: CodingKey {
case firstName
case lastName
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
// 3
// Decode firstName & lastName
firstName = try container.decode(String.self, forKey: CodingKeys.firstName)
lastName = try container.decode(String.self, forKey: CodingKeys.lastName)
// 4
// Extract studentId from coding path
studentId = container.codingPath.first!.stringValue
}
}