将 [[[Double]]] 施放回 [Double]
Cast a [[[Double]]] back to [Double]
我下载了一个 JSON 文件。在其中,重复对象是 2 种类型中的一种 - [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。所以,我假设它有点像:
{
"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)
}
}
}
As long as your key
s in the JSON and the properties in your struct
are identical, you don't need to provide 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)
}
我下载了一个 JSON 文件。在其中,重复对象是 2 种类型中的一种 - [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。所以,我假设它有点像:
{
"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)
}
}
}
As long as your
key
s in the JSON and the properties in yourstruct
are identical, you don't need to provideCodingKeys
.
现在解码:
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)
}