I have var toPlotLines:[Int] = [200, 300, 400, 500, 600, 322, 435] and I want to retrieve the first four integers from the array. Can I do that without having to loop in Swift. I tried this graphView.graphPoints = toPlotLines[0..<n] where graphPoints is an empty integer array but, I keep getting this error:
Cannot subscript a value of type [int]
The error message is misleading. The problem is that toPlotLines[0 ..< n]
is not an Array but an ArraySlice:
The Array-like type that represents a sub-sequence of any Array, ContiguousArray, or other ArraySlice.
To create a "real array", use
graphView.graphPoints = Array(toPlotLines[0 ..< n])
From Array<Int> to ArraySlice<Int>
When you subscript to an Array, the type of the returned object is an ArraySlice:
let toPlotLines = [200, 300, 400, 500, 600, 322, 435] // type: [Int]
let arraySlice = toPlotLines[0 ..< 4] // type: ArraySlice<Int>
You can learn more about ArraySlice with ArraySlice Structure Reference.
From ArraySlice<Int> to Array<Int>
On one hand, ArraySlice conforms to CollectionType protocol that inherits itself from SequenceType. On the other hand, Array has an initializer init(_:) with the following declaration:
init<S : SequenceType where S.Generator.Element == _Buffer.Element>(_ s: S)
Therefore, it's possible to get a new Array from an ArraySlice easily:
let toPlotLines = [200, 300, 400, 500, 600, 322, 435]
let arraySlice = toPlotLines[0 ..< 4]
let newArray = Array(arraySlice)
print(newArray) // prints: [200, 300, 400, 500]
From ArraySlice<Int> to Array<String>
Because ArraySlice conforms to SequenceType, you can use map (or other functional methods like filter and reduce) on it. Thereby, you are not limited to get an Array<Int> from your ArraySlice<Int>: you can get an Array<String> (or any other array type that would make sense) from your ArraySlice<Int>.
let toPlotLines = [200, 300, 400, 500, 600, 322, 435]
let arraySlice = toPlotLines[0 ..< 4]
let stringArray = arraySlice.map { String($0) }
print(stringArray) // prints: ["200", "300", "400", "500"]
Related
I am using this article to communicate with an IoT sensor via BLE. In the article, this quote is mentioned:
The first two bytes do not seem to belong to the data (probably a prefix to denote that it is a data packet), but the remaining ones are more interesting. For the accelerometer, we get three signed 16 bit integers (little endian), which can simply be scaled to the range we set up to get our setup sequence. So the +/-2^15 range of the signed 16bit integer corresponds to the +/-16g, resulting in a factor 1/2048. To get the acceleration in m/s², we apply a factor of 9.81/2048. So, the corresponding bluetooth part reads:
<output char="326a9006-85cb-9195-d9dd-464cfbbae75a" conversion="int16LittleEndian" offset="2" length="2">accXRaw</output>
<output char="326a9006-85cb-9195-d9dd-464cfbbae75a" conversion="int16LittleEndian" offset="4" length="2">accYRaw</output>
<output char="326a9006-85cb-9195-d9dd-464cfbbae75a" conversion="int16LittleEndian" offset="6" length="2">accZRaw</output>
To read this code, I am running this Swift code:
private func sensor(from characteristic: CBCharacteristic) {
guard let characteristicData = characteristic.value,
let _ = characteristicData.first else { return }
let data = characteristic.value!
var values = [UInt8](repeating: 0, count: data.count)
data.copyBytes(to: &values, count: data.count)
print("values = \(values)")
}
The result once I do a print is:
values = [3, 4, 250, 255, 199, 249, 91, 191]
Alike the article mentions, I can confirm that the first two bytes do not belong to any data, and are consistently repeating. Bytes values[2-7] are constantly changing, which makes me more confident that the pairs represent accXRaw, accYRaw, and accZRaw. What I want to do now is convert the pairs to doubles.
For example:
values[2], values[3] = [250 255] (accXRaw)
values[4], values[5] = [199 249] (accYRaw)
values[6], values[7] = [91 191] (accZRaw)
In the article, the author does this via a int16 little endian. I want to do the same with swift 5, but not sure if I am doing it correctly. Here is my code:
let xAxis = Float(bitPattern: UInt32(littleEndian: [values[2], values[3], 0x00, 0x00].withUnsafeBytes { $0.load(as: UInt32.self) }))
let yAxis = Float(bitPattern: UInt32(littleEndian: [values[4], values[5], 0x00, 0x00].withUnsafeBytes { $0.load(as: UInt32.self) }))
let zAxis = Float(bitPattern: UInt32(littleEndian: [values[6], values[7], 0x00, 0x00].withUnsafeBytes { $0.load(as: UInt32.self) }))
print("x=\(xAxis), y=\(yAxis), z=\(zAxis)");
The resulting printout is:
values = [3, 4, 250, 255, 199, 249, 91, 191]
x=9.1827e-41, y=8.9603e-41, z=6.8645e-41
These numbers just look weird, and I suspect I am doing something wrong. Am I reading the byte pairs correctly ( at least in line with the article ) ? If not, what mistakes did I make?
Your issue there is that you are not suppose to initialize your Float using the bitPattern initializer and/or use the UInt32(littleEndian:) initializer. What you need is to convert those 2 bytes to Int16, coerce it to Float and then multiply by the factor of 9.81/2048 to get its acceleration.
Expanding on that, you can create a Numeric initializer that takes an object that conforms to DataProtocol (Data or Bytes [UInt8]):
extension Numeric {
init<D: DataProtocol>(_ data: D) {
var value: Self = .zero
let size = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0)} )
assert(size == MemoryLayout.size(ofValue: value))
self = value
}
}
Then you can initialize your Int16 object with the subdata (two bytes).
let bytes: [UInt8] = [3, 4, 250, 255, 199, 249, 91, 191]
let xData = bytes[2..<4]
let yData = bytes[4..<6]
let zData = bytes[6..<8]
let factor: Float = 9.81/2048
let xAxis = Float(Int16(xData)) * factor
let yAxis = Float(Int16(yData)) * factor
let zAxis = Float(Int16(zData)) * factor
print("x:", xAxis, "y:", yAxis, "z:", zAxis) // x: -0.028740235 y: -7.6305327 z: -79.27036
I am trying to round all elements in the vector using new static function convertElements from Accelerate framework.
Sadly i don't know how to use it.
Here is what i tried:
let a: [Double] = [10.6, 20, 30.8, 40, 50, 60, 70, 80, 90, 100]
var b = [Int](repeating: 0, count: a.count)
var round: vDSP.RoundingMode = vDSP.RoundingMode.towardNearestInteger
vDSP.convertElements(of: a, to: &b, rounding: round)
This code throws error:
error: ambiguous reference to static method 'convertElements(of:to:rounding:)'
vDSP.convertElements(of: a, to: &b, rounding: vDSP.RoundingMode.towardNearestInteger)
Any idea how to use this function?
Seems like setting value of vDSP.RoundingMode type is the problem.
You're using the wrong type for the to: array. It needs to be [Int32], not [Int].
Change:
var b = [Int](repeating: 0, count: a.count)
to:
var b = [Int32](repeating: 0, count: a.count)
In the link you provided, the definition of the function is:
static func convertElements<U, V>(of source: U, to destination: inout V,
rounding: vDSP.RoundingMode) where U : AccelerateBuffer,
V : AccelerateMutableBuffer, U.Element == Double, V.Element == Int32
Notice that V.Element is Int32.
As noted by #MartinR in the comments, other types are possible including Int8, UInt8, Int16, UInt16, and UInt32. All of the calls are detailed here.
I try to convert my UInt8 array to an explicit value but I try in several ways but I can't get values that I can understand.
How have i to do to get explicit values?.
My array of UInt8 :
[216, 61, 233, 124, 240, 144, 66, 244]
My code :
guard let characteristicData = characteristic.value else { return "Error" }
let count = (characteristicData.count) / MemoryLayout<UInt8>.size
var array = [UInt8](repeating: 0, count: count)
characteristicData.copyBytes(to: &array, count:count * MemoryLayout<UInt8>.size)
let characters = array.map { Character(UnicodeScalar($0)) }
let result = String(Array(characters))
print(array)
print(result.utf8)
My output:
Ø=é|ðBô
Consider a situation where we want to have a dictionary of arrays, with each array being a homogeneous collection of values of some type (which may be a struct or a primitive type). I'm currently using the ObjectIdentifier of the type defining it thusly:
let pInts : [UInt32] = [4, 6, 99, 1001, 2032]
let pFloats : [Float] = [3.14159, 8.9]
let pBools : [Bool] = [true, false, true]
let myDataStructure : [ObjectIdentifier : [Any]] = [
ObjectIdentifier(Float.self) : pFloats,
ObjectIdentifier(UInt32.self) : pInts,
ObjectIdentifier(Bool.self) : pBools
]
The issue here is that when traversing the data structure, Swift doesn't know that the objects in each list are homogeneous. Since swift is statically typed, I'm guessing it is not possible to typecast the [Any] lists using the ObjectIdentifier keys. Consider this traversal pseudocode:
for (typeObjId, listOfValuesOfSometype) in myDataStructure {
// do something like swap values around in the array,
// knowing they are homogeneously but anonymously typed
}
So, is there some metatype machinery I can concoct to represent this data structure in a way that does not anticipate the list of actual types that will have arrays in it?
I'm not exactly sure what you want to accomplish, Inside the dictionary loop the arrays will always be of type Any, but if you want to move items in the arrays around, you could just do that. Just reassign the array first to a var and then put it back in the dictionary.
If you do want to loop through the items of a specific type, then you could use the array helper function below.
func testX() {
let pInts: [UInt32] = [4, 6, 99, 1001, 2032]
let pFloats: [Float] = [3.14159, 8.9]
let pBools: [Bool] = [true, false, true]
var myDataStructure: [ObjectIdentifier: [Any]] = [
ObjectIdentifier(Float.self): pFloats,
ObjectIdentifier(UInt32.self): pInts,
ObjectIdentifier(Bool.self): pBools
]
// Swap the first 2 items of every array
for d in myDataStructure {
var i = d.value
if i.count > 1 {
let s = i[0]
i[0] = i[1]
i[1] = s
}
myDataStructure[d.key] = i
}
// Now dump all data per specific type using the array helper function.
for i: UInt32 in array(myDataStructure) {
print(i)
}
for i: Float in array(myDataStructure) {
print(i)
}
for i: Bool in array(myDataStructure) {
print(i)
}
}
func array<T>(_ data: [ObjectIdentifier: [Any]]) -> [T] {
return data[ObjectIdentifier(T.self)] as? [T] ?? []
}
Here are 2 arrays: countriesVotedKeys and dictionnaryCountriesVotes.
I need to build a dictionary, whose keys are all the items from countriesVotedKeys, and its values are all the items from dictionnaryCountriesVotes. Both arrays contains same number of elements.
I've tried many things, but none lead to desired result.
for value in self.countriesVotedValues! {
for key in self.countriesVotedKeys! {
self.dictionnaryCountriesVotes![key] = value
}
}
I can clearly see why this code produce bad result: second array is iterated in its entirity at each iteration of first array. I also tried a classical for var i= 0, var j= 0;...... but it seems this kind of syntax is not allowed in swift.
In short, i'm stuck. Again.
Swift 4
let keys = ["key1", "key2", "key3"]
let values = [100, 200, 300]
let dict = Dictionary(uniqueKeysWithValues: zip(keys, values))
print(dict) // "[key1: 100, key3: 300, key2: 200]"
Swift 3
var dict: [String: Int] = [:]
for i in 0..<keys.count {
dict[keys[i]] = values[i]
}
Use NSDictionary's convenience initializer:
let keys = ["a", "b", "c"]
let values = [1,2,3]
var dict = NSDictionary(objects: values, forKeys: keys) as [String: Int]