#arrays #swift #swift5 #typecasting-operator
#массивы #swift #swift5 #приведение типов-оператор
Вопрос:
Я создал структуру чтения файла, содержащую данные, смещения и методы чтения (каким-то образом fread() сбивал меня с толку).
Я заработал, и теперь хочу внедрить в него метод, который будет принимать n x m матричных терминов и выводить матрицу значений. (Аналогично fread(FileID, [n m ], «(тип данных)») в matlab).
Вот моя идея
// should be able to handle all sorts of datatypes and output n by m matrix.
mutating func matRead( dim : [[Int]], dtype : Int ){
if dim.count != 2{
fatalError("Dimensions dont match "n by m" in matRead")
}
// make sure to preallocate with zeros.
var mat_Out : typecast[dtype][2].self = []
}
У меня есть словарь типизации, который выглядит так
// typecast dictionary key : [ array_type, byte, element_type ]
let typecast : [Int16:[Any]] = [ 1: [ [UInt8].self , 1, "uint8"],
2: [ [UInt16].self , 2, "uint16"], // use .self to reference data type itself.
3: [ [UInt32].self , 4, "uint32"],
4: [ [Int8].self , 1, "int8" ],
5: [ [Int16].self , 2, "int16" ],
6: [ [Int32].self , 4, "int32" ],
7: [ [Float32].self, 4, "float32"],
8: [ [Float64].self, 8, "float64"],
12:[ [Int32].self , 4, "int32" ] ]
Вот вопрос: строка 8 функции matRead() не работает. Swift не понимает, что я пытаюсь использовать словарь приведения типов для присвоения новому типу массива выходной матрицы. Я также пробовал «как» var mat_Out : Any = [] as typecast[dtype][0]
, также с той же ошибкой (компилятор Swift думает, что я имел в виду вывести скобки наружу).
В качестве альтернативы я мог бы пройти долгий путь и выполнить типизацию вручную на основе строковых значений (уже приходилось это делать: см. Ниже Код fread struct), но если есть другой способ, это значительно сэкономит время.
Структура чтения файлов ниже (избыточное использование контрольных счетчиков, но я ее не очистил)
struct fRead {
var off : Int = 0
let data : Data
mutating func resetOffsetToZero() {
off = 0
}
mutating func setOffset( _ to : Int ) {
off.self = to
}
mutating func moveOffset( _ by : Int) {
off.self = by
}
func getOffset() -> Int {
return off
}
// reading without specified number of elements defaults to 1.
// these mutating funcs vary only in their output type and byte offset size.
mutating func int32Read(count : Int = 1) -> [Int32] {
var int32out : [Int32] = []
if count > 1 {
for i in 0...count-1 {
int32out.append( Int32( data.subdata(in: off i * 4..<(off (i 1) * 4) ).withUnsafeBytes{ $0.load(as: Int32.self )} ))
}
off = count * 4
}
else if count == 1 {
int32out = [ Int32( data.subdata(in: off..<(off 4) ).withUnsafeBytes{ $0.load(as: Int32.self )} )]
off = 4
}
else if count == 0 {
return []
} else if count < 0{
print("Warning, fReadint32Read( count : Int = 1) called with a negative count, returning empty array.")
}
return int32out
}
mutating func int16Read(count : Int = 1) -> [Int16] {
var int16out : [Int16] = []
if count > 1 {
for i in 0...count-1 {
int16out.append( data.subdata(in: off i * 2..<(off (i 1) * 2) ).withUnsafeBytes{ $0.load(as: Int16.self )} )
}
off = count * 2
}
else if count == 1 {
int16out = [ data.subdata(in: off..<(off 2) ).withUnsafeBytes{ $0.load(as: Int16.self )} ]
off = 2
}
else if count == 0 {
return []
} else if count < 0 {
print("Warning, fRead.int16Read( count : Int = 1) called with a negative count, returning empty array.")
}
return int16out
}
mutating func float64Read(count : Int = 1) -> [Float64] {
var float64out : [Float64] = []
if count > 1 {
for i in 0...count-1 {
float64out.append( data.subdata(in: off i * 8..<(off (i 1) * 8) ).withUnsafeBytes{ $0.load(as: Float64.self )} )
}
off = count * 8
}
else if count == 1 {
float64out = [ data.subdata(in: off..<(off 8) ).withUnsafeBytes{ $0.load(as: Float64.self )} ]
off = 8
}
else if count == 0 {
return []
} else if count < 0 {
print("Warning, fRead.int16Read( count : Int = 1) called with a negative count, returning empty array.")
}
return float64out
}
mutating func uint32Read(count : Int = 1) -> [UInt32] {
var uint32out : [UInt32] = []
if count > 1 {
for i in 0...count-1 {
uint32out.append( data.subdata(in: off i * 4..<(off (i 1) * 4) ).withUnsafeBytes{ $0.load(as: UInt32.self )} )
}
off = count * 4
}
else if count == 1 {
uint32out = [ data.subdata(in: off..<(off 4) ).withUnsafeBytes{ $0.load(as: UInt32.self )} ]
off = 4
}
else if count == 0 {
return []
} else if count < 0 {
print("Warning, fRead.int16Read( count : Int = 1) called with a negative count, returning empty array.")
}
return uint32out
}
mutating func int64Read(count : Int = 1) -> [Int64] {
var int64out : [Int64] = []
if count > 1 {
for i in 0...count-1 {
int64out.append( Int64( data.subdata(in: off i * 4..<(off (i 1) * 8) ).withUnsafeBytes{ $0.load(as: Int64.self )} ))
}
off = count * 8
}
else if count == 1 {
int64out = [ Int64( data.subdata(in: off..<(off 8) ).withUnsafeBytes{ $0.load(as: Int64.self )} )]
off = 8
}
else if count == 0 {
return []
} else if count < 0{
print("Warning, fReadint64Read( count : Int = 1) called with a negative count, returning empty array.")
}
return int64out
}
// should be able to handle all sorts of datatypes and output n by m matrix.
mutating func matRead( dim : [[Int]], dtype : Int ){
if dim.count != 2{
fatalError("Dimensions dont match "n by m" in matRead")
}
// make sure to preallocate with zeros.
var mat_Out : Any = [] as typecast[dtype][0]
}
}
// I only discovered afterwards that 0...0 range works! So all the testing for ==1 , == 0 wasn't necessary
Комментарии:
1. Вы пытаетесь преобразовать все
xxxRead
методы в один метод?2. В этом нет необходимости, потому что в моей основной программе я организовал все разные чтения. Это было бы чище, объединившись в один метод, но я справился без этого. Я стараюсь не делать то же самое при создании моего матричного считывателя.
Ответ №1:
Разве общее решение не было бы лучшим способом продвижения вперед здесь? Ниже приведена общая версия, когда элементы являются целыми числами, поэтому для floats () необходима аналогичная функция BinaryFloatingPoint
.
mutating func matRead<T: BinaryInteger>(count: Int = 1) -> [T] {
var intOut : [T] = []
let width = T().bitWidth / 8
if count > 1 {
for i in 0...count-1 {
intOut.append( T( data.subdata(in: off i * 4..<(off (i 1) * width) ).withUnsafeBytes{ $0.load(as: T.self )} ))
}
off = count * width
}
else if count == 1 {
intOut = [ T( data.subdata(in: off..<(off width) ).withUnsafeBytes{ $0.load(as: T.self )} )]
off = width
}
else if count == 0 {
return []
} else if count < 0{
print("Warning, fReadint64Read( count : Int = 1) called with a negative count, returning empty array.")
}
return intOut
}
Обратите внимание, что в приведенном выше коде есть «ошибка», я не был уверен, что заменить 4 на in i * 4..<(off (i 1)
, поскольку вы использовали это число так непоследовательно между вашими функциями. Я думаю, так и должно быть width / 2
, но я оставляю это вам, чтобы обновить эту часть.
Комментарии:
1. В итоге это оказалось близко к тому, что я в итоге сделал. Я пытаюсь использовать эту форму функций: (их будет две)
2. Отличная идея, я пытаюсь привести функцию в соответствие с вашим ответом для двоичного (Integer / FloatingPiont)
mutating func fromfileBI<T : BinaryInteger>(count : Int = 1) -> [T]? { let byteSize = MemoryLayout<T>.stride var swiftTypeOut : [T] = [] if count > 1 { swiftTypeOut = [T].init(repeating: 0, count: count) for i in 0...count-1 { swiftTypeOut[i] = data.subdata(in: off i * byteSize..<off (i 1) * byteSize ).withUnsafeBytes{ $0.load(as: T.self )} } off = count * byteSize } }