使用Codable解析JSON后,如何将[[[Double]]]转回[Double]?
嘿,我明白你遇到的麻烦了——解析时为了统一类型把单层[Double]转成了[[[Double]]],现在想转回来直接用as! [Double]失败,这是因为Swift的类型系统认死理,哪怕你的三层数组实际只是嵌套了一层,它也不会自动帮你转换成单层。下面给你几个实用的解决方案:
方案1:用计算属性直接扁平化数组
如果你的结构体里已经把所有数据都存成了[[[Double]]],那最简单的方式就是给结构体加一个计算属性,专门负责把三层数组扁平成单层:
struct YourDataModel: Codable { let rawData: [[[Double]]] // 计算属性:自动扁平化数组 var flattenedData: [Double] { rawData.flatMap { $0.flatMap { $0 } } } }
之后你直接用model.flattenedData就能拿到单层的[Double]数组,不管原始数据本来就是三层还是从单层转过来的,都能正常处理。
方案2:用枚举保留原始类型(更灵活)
其实更推荐的做法是在解析阶段就保留原始类型的信息,不用强行统一成三层数组。可以定义一个遵循Codable的枚举来处理两种情况:
enum NumericDataSet: Codable { case singleLayer([Double]) case tripleLayer([[[Double]]]) // 统一获取单层数组的属性 var asSingleArray: [Double] { switch self { case .singleLayer(let array): return array case .tripleLayer(let array): return array.flatMap { $0.flatMap { $0 } } } } // 自定义解码逻辑 init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() // 先尝试解码成单层数组 if let singleArray = try? container.decode([Double].self) { self = .singleLayer(singleArray) } // 不行就解码成三层数组 else if let tripleArray = try? container.decode([[[Double]]].self) { self = .tripleLayer(tripleArray) } // 都不是就抛出错误 else { throw DecodingError.dataCorruptedError( in: container, debugDescription: "数据类型不支持,只能是[Double]或[[[Double]]]" ) } } // 自定义编码逻辑(如果需要再转成JSON的话) func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() switch self { case .singleLayer(let array): try container.encode(array) case .tripleLayer(let array): try container.encode(array) } } }
然后你的结构体就可以用这个枚举作为属性:
struct YourDataModel: Codable { let data: NumericDataSet }
之后用model.data.asSingleArray就能直接拿到单层数组,还能通过枚举的case判断原始数据的类型,比强行统一类型灵活多了。
方案3:针对性转换原本的单层数组
如果你的三层数组里,一部分是原本的单层转来的(结构是[[[a,b,c]]]),一部分是真正的三层数组,那可以写个工具函数来针对性转换:
func convertToSingleIfPossible(_ tripleArray: [[[Double]]]) -> [Double] { // 判断是否是单层转来的三层数组 if tripleArray.count == 1, let middleArray = tripleArray.first, middleArray.count == 1 { return middleArray.first ?? [] } // 真正的三层数组就直接扁平化 return tripleArray.flatMap { $0.flatMap { $0 } } }
调用的时候直接传你的三层数组进去就行,会自动判断并返回合适的单层数组。
为什么强制转换会失败?
最后说下为啥as! [Double]不行:Swift是强类型语言,[[[Double]]]和[Double]是完全不同的类型,哪怕你的三层数组实际只有一层嵌套,类型系统也不会把它当成单层数组,强行用as!只会触发运行时崩溃,必须通过扁平化或者类型判断的方式来转换。
内容的提问来源于stack exchange,提问作者jingo_man

