【问题标题】:Cast a [[[Double]]] back to [Double]将 [[[Double]]] 投射回 [Double]
【发布时间】:2018-03-18 22:52:29
【问题描述】:

我有一个下载的 JSON 文件。在其中,有重复的对象是两种类型中的一种 - [Double][[[Double]]]

我正在尝试对自定义结构使用 Codable 协议来将数据转储到对象中。为了解决上述问题,我实际上将更简单的[Double] 转换为相同的[[[Double]]] 类型。

稍后,当使用这些数据时,我正在努力将其转换回一个更简单的单层数组。我希望我可以强制将其强制转换为单个 as! [Double] 类型。我还能怎么做?每个数组层都需要一个“for in”循环吗?

另外,我如何调整我的 Geometry 结构,这样我就不会为这个属性使用不同类型的数组?我想知道coordinates 属性是否可以更改为Any 类型或其他类型?

struct Geometry: Codable {
    let coordinates: [[[Double]]]
    let type: String

    enum CodingKeys: String, CodingKey {
        case coordinates
        case type
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        type = try container.decode(String.self, forKey: .type)

        if type == "Point" {
            let typeFromMapbox = try container.decode([Double].self, forKey: .coordinates)
            coordinates = [[typeFromMapbox]]
        } else { // THIS IS A POLYGON
            coordinates = try container.decode([[[Double]]].self, forKey: .coordinates)
        }
    }
}

我只是从 Swift 开始和学习

感谢任何帮助、指示或见解

谢谢

【问题讨论】:

  • 发布 JSON。这将使每个人都更容易为您提供帮助。

标签: arrays swift casting codable


【解决方案1】:

您没有提供实际的 JSON。所以,我认为它有点像:

{
    "geometries" :
    [
        {
            "coordinates" : [1.0, 2.0],
            "type" : "flat"
        },
        {
            "coordinates" : [[[111.0, 222.0]]],
            "type" : "multi"
        }
    ]
}

基于上述结构,您的根级数据类型将是:

struct Root: Codable {
    let geometries: [Geometry]
}

那么,您的Geometry 将被定义为:

struct Geometry: Codable {
    // As long as your coordinates should be at least a flat array. Multi dimensional array will be handled by `Coordinate` type
    let coordinates: [Coordinate]
    let type: String
}

现在是Coordinate 数组。这可能是Double 类型或[[Double]] 类型。所以用enum 包装它:

enum Coordinate: Codable {
    case double(Double)
    case arrayOfDoubleArray([[Double]])

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        do {
            self = try .double(container.decode(Double.self))
        } catch DecodingError.typeMismatch {
            do {
                self = try .arrayOfDoubleArray(container.decode([[Double]].self))
            } catch DecodingError.typeMismatch {
                throw DecodingError.typeMismatch(Coordinate.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Coordinate type doesn't match"))
            }
        }
    }

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

只要您在 JSON 中的keys 和您在struct 中的属性相同,您就不需要提供CodingKeys

现在解码:

let jsonData = """
{
    "geometries" :
    [
        {
            "coordinates" : [1.0, 2.0],
            "type" : "flat"
        },
        {
            "coordinates" : [[[111.0, 222.0]]],
            "type" : "multi"
        }
    ]
}
""".data(using: .utf8)!

do {
    let root = try JSONDecoder().decode(Root.self, from: jsonData)
    root.geometries.forEach({ (geometry) in
        geometry.coordinates.forEach({ (coordinate) in
            if case .double(let double) = coordinate {
                print(double)   // 1.0, 2.0
            }
            if case .arrayOfDoubleArray(let array) = coordinate {
                print(array)    // [[111.0, 222.0]]
            }
        })
    })
} catch {
    print(error)
}

【讨论】:

  • .@nayem,感谢您的回复。您猜对了 JSON 格式,所以我不会提供其他示例。似乎您在编码和解码过程中做了更多的“工作”,而且看起来并不比将两种类型都保留为三重数组并在需要时根据需要展开。我主要是在询问是否有特殊/快捷方式/首选技术。
猜你喜欢
  • 2013-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-08
  • 1970-01-01
  • 2012-12-02
相关资源
最近更新 更多