Arrays 在Swift中读取JSON中的嵌套数组和元组

Arrays 在Swift中读取JSON中的嵌套数组和元组,arrays,json,swift,tuples,decode,Arrays,Json,Swift,Tuples,Decode,我有一些数据通过JSON传递,JSON是一个包含数组的元组数组,我无法从中提取数据。我尝试过使用不同的类型,但唯一有效的是(任何类型),我无法进一步细分。 JSON: { ... // stuff that I can easily read, like "WIDTH": 33, ... "WIDTHS_ROI_PAIRS": [[80, [0,0,200,160]], [145, [0, 240, 100, 60]], [145, [100, 240, 100, 60]]]

我有一些数据通过JSON传递,JSON是一个包含数组的元组数组,我无法从中提取数据。我尝试过使用不同的类型,但唯一有效的是(任何类型),我无法进一步细分。 JSON:

{
  ...
  // stuff that I can easily read, like "WIDTH": 33,
  ... 
  "WIDTHS_ROI_PAIRS": [[80, [0,0,200,160]], [145, [0, 240, 100, 60]], [145, [100, 240, 100, 60]]]
}
它要进入的结构:

struct WidthRoiPair: Codable {
    let width: Int
    let roi: [Int]
}
我想做什么(它不工作,把它当作伪代码):

尝试p[0]而不是p.0也不起作用,尝试将JSON直接转换为我需要的内容,类似这样:

let widthRoiPairsTmp = json["WIDTHS_ROI_PAIRS"] as! [(Int, [Int])]
也不起作用。我尝试使用JSONDecoder(),但我不知道如何将json[“WIDTHS\u ROI\u PAIRS”](或其元素)传递给它(如何将其转换回数据)。 我相信对任何一个对Swift稍有经验的人来说,答案都是显而易见的,但目前我完全被卡住了…

你可以试试

struct Root: Codable {
    let widthsRoiPairs: [[InnerItem]]

    enum CodingKeys: String, CodingKey {
        case widthsRoiPairs = "WIDTHS_ROI_PAIRS"
    }
}

enum InnerItem: Codable {
    case integer(Int)
    case integerArray([Int])

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(Int.self) {
            self = .integer(x)
            return
        }
        if let x = try? container.decode([Int].self) {
            self = .integerArray(x)
            return
        }
        throw DecodingError.typeMismatch(InnerItem.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for InnerItem"))
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .integer(let x):
            try container.encode(x)
        case .integerArray(let x):
            try container.encode(x)
        }
    }
}

用法


谢谢,效果很好。我惊讶的是,没有一种更简单的方式来解析数据:有一点结构:只需编写自己的解码器就显得太多了。@ BUCC最好是将JSON结构从<代码> [80,[0,02160] ] /<代码>改为<代码> [[ 80 ],[0,0200 160] ] < /代码>,因此您可以考虑它嵌套int数组,您还应该知道,Codable与jsonyou's right@Sh_Khan的复杂性齐头并进,然后我可以定义widthsRoiPairs:[[[Int]]],这样就不需要使用InnerItem类和额外的编码/解码代码(顺便说一句,我很惊讶您这么快就把它组合起来了)。JSON格式是从其他代码中继承过来的,并且更直观,但是我可以考虑改变它来简化代码。无论如何,很遗憾我们不能使用元组定义宽度对:[(Int,[Int])]
struct Root: Codable {
    let widthsRoiPairs: [[InnerItem]]

    enum CodingKeys: String, CodingKey {
        case widthsRoiPairs = "WIDTHS_ROI_PAIRS"
    }
}

enum InnerItem: Codable {
    case integer(Int)
    case integerArray([Int])

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(Int.self) {
            self = .integer(x)
            return
        }
        if let x = try? container.decode([Int].self) {
            self = .integerArray(x)
            return
        }
        throw DecodingError.typeMismatch(InnerItem.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for InnerItem"))
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .integer(let x):
            try container.encode(x)
        case .integerArray(let x):
            try container.encode(x)
        }
    }
}
let str = """

            {
            "WIDTHS_ROI_PAIRS": [[80, [0,0,200,160]], [145, [0, 240, 100, 60]], [145, [100, 240, 100, 60]]]
            }

"""

    do {

        let res = try JSONDecoder().decode(Root.self, from: str.data(using: .utf8)!)

        res.widthsRoiPairs.forEach {

            $0.forEach {

                switch $0 {
                case .integer(let w) :
                    print(w)
                case .integerArray(let arr) :
                    print(arr)
                }

            }
        }

    }
    catch {

        print(error)
    }