如何从JSON建模Struct,其中某些高级属性没有键

时间:2019-01-20 20:26:58

标签: json swift codable decodable

我正在尝试创建一个结构以对下面的JSON建模,其中高级属性(“蓝色团队”和“绿色团队”)没有指定的键。

var transac = [{id: 3,sourceAccount: 'A',targetAccount: 'B',amount: 100,category: 'eating_out',time: '2018-03-02T10:34:30.000Z'},{id: 1,sourceAccount: 'A',targetAccount: 'B',amount: 100,category: 'eating_out',time: '2018-03-02T10:33:00.000Z'},{id: 6,sourceAccount: 'A',targetAccount: 'C',amount: 250,category: 'other',time: '2018-03-02T10:33:05.000Z'},{id: 4,sourceAccount: 'A',targetAccount: 'B',amount: 100,category: 'eating_out',time: '2018-03-02T10:36:00.000Z'},{id: 2,sourceAccount: 'A',targetAccount: 'B',amount: 100,category: 'eating_out',time: '2018-03-02T10:33:50.000Z'},{id: 5,sourceAccount: 'A',targetAccount: 'C',amount: 250,category: 'other',time: '2018-03-02T10:33:00.000Z'}];

const result = transac.map(t => ({
    key: JSON.stringify([t.sourceAccount, t.targetAccount, t.amount, t.category]), 
    epoch: Date.parse(t.time), 
    t
})).sort((a,b) => 
    a.key.localeCompare(b.key) || a.epoch - b.epoch || a.t.id - b.t.id
).reduce(([acc, prev], curr) => {
    if (!prev || curr.key != prev.key || curr.epoch - prev.epoch > 60000) acc.push([]);
    acc[acc.length-1].push(curr.t);
    return [acc, curr];
}, [[]])[0];

console.log(result);

我相信我已经接近了,但是我不确定如何代表const duplicates = result.filter(a => a.length > 1); { "Teams": [ { "Blue Team": { "motto": "We're the best", "players": [ { "name": "Bob", "skill": "jumping really high", "birthday": 1546326611, }, { "name": "Julie", "skill": "really strong", "birthday": 1546413133, }, { "name": "Kirsten", "skill": "smarty pants", "birthday": 1546499716, } ] }, "Green Team": {... // same structure as above } } ] } 。这是我到目前为止的内容:

Blue Team

3 个答案:

答案 0 :(得分:1)

我想您要在[String: Team]结构中使用AllTeams吗?

您可以这样做:

struct AllTeams: Decodable {
    let teams: [String: Team]

    enum CodingKeys: String, CodingKey {
        case teams = "Teams"
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        teams = (try container.decode([[String: Team]].self, forKey: .teams))[0]
    }
}

struct Team: Codable {
    let motto: String
    let players: [Player]
}

struct Player: Codable {
    let name, skill: String
    let birthday: Date
}

解码:

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .secondsSince1970
let teams = try! decoder.decode(AllTeams.self, from: json)
print(teams.teams["Blue Team"].motto)

答案 1 :(得分:0)

正确的json(因为您的json不完整,并且在生日密钥结尾包含错误的,

{
    "Teams": [{
        "Blue Team": {
            "motto": "We're the best",
            "players": [{
                    "name": "Bob",
                    "skill": "jumping really high",
                    "birthday": 1546326611
                },
                {
                    "name": "Julie",
                    "skill": "really strong",
                    "birthday": 1546413133
                },
                {
                    "name": "Kirsten",
                    "skill": "smarty pants",
                    "birthday": 1546499716
                }
            ]
        },
        "Green Team": {
            "motto": "We're the best",
            "players": [{
                    "name": "Bob",
                    "skill": "jumping really high",
                    "birthday": 1546326611
                },
                {
                    "name": "Julie",
                    "skill": "really strong",
                    "birthday": 1546413133
                },
                {
                    "name": "Kirsten",
                    "skill": "smarty pants",
                    "birthday": 1546499716
                }
            ]
        }
    }]
}

2键

struct Root: Codable {
    let teams: [Team]

    enum CodingKeys: String, CodingKey {
        case teams = "Teams"
    }
}

struct Team: Codable {
    let blueTeam, greenTeam: BlueTeamClass

    enum CodingKeys: String, CodingKey {
        case blueTeam = "Blue Team"
        case greenTeam = "Green Team"
    }
}

struct BlueTeamClass: Codable {
    let motto: String
    let players: [Player]
}

struct Player: Codable {
    let name, skill: String
    let birthday: Int
}

用于动态键

struct Root: Codable {
    let teams: [[String:Item]]

    enum CodingKeys: String, CodingKey {
        case teams = "Teams"
    }
}

struct Item: Codable {
    let motto: String
    let players: [Player]
}

struct Player: Codable {
    let name, skill: String
    let birthday: Int
}

解码

do {
     let res = try JSONDecoder().decode(Root.self,from:data)
     print(res)
   }
 catch {
    print(error)
}        

答案 2 :(得分:0)

您确实很亲密。

当您想将团队解码为词典时,将结构更改为

struct AllTeams: Codable {
    let Teams: [[String : Team]]

    struct Team: Codable {
        let motto: String
        let players: [Player]
    }

    struct Player: Codable {
        let name: String
        let skill: String
        let birthday: Date
    }
}

并解码

 let decoder = JSONDecoder()
 decoder.dateDecodingStrategy = .secondsSince1970
 let result = try decoder.decode(AllTeams.self, from: data)

生日整数被解码为Date

要获得更复杂的解决方案,以自定义CodingKeys将团队密钥包含在Team结构中,请查看this answer

注意:

鼓励您遵守命名约定,并添加CodingKeys将大写键映射到小写结构成员