I have a situation where I needed to convert NSNumber
2D array to Float
2D array, so I did it like this:
var numArr:[[NSNumber]]()
//fill values
let floatArr = numArr.map { 0ドル.map { 0ドル.floatValue} }
It's working fine, no issues!
But I wondering if there's any better way to handle this?
1 Answer 1
Your code is fine, an equivalent method in Swift 3 would be
let floatArr = numArr.map { 0ドル.map { Float(0ドル) } }
You get the same result with less code by using the
bridging cast from NSNumber
to Float
, which works for (nested)
arrays as well:
if let floatArr = numArr as [[Float]] { ... }
Actually I don't know of any case (in Swift 3) where this cast can fail.
Things change a bit in Swift 4, as a consequence of SE 0170 - NSNumber bridging and Numeric types. Your code still works fine, and is equivalent to
let floatArr = numArr.map { 0ドル.map { Float(truncating: 0ドル) } }
The truncating initializers where introduced because not every
Number
can be converted to a scalar value without loosing information,
there are also failable init?(exactly:)
initializers.
Now the bridged cast can fail
- for numbers which are not exactly representable as a
Float
, such asDouble(1.1)
, - for numbers which exceed the range of
Float
.
(The first case is currently discussed at https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170612/037499.html and may change in the future.)
Example:
let numArr = [
[ NSNumber(value: 1.1), NSNumber(value: 2.0) ],
[ NSNumber(value: Double.greatestFiniteMagnitude) ],
]
if let floatArr = numArr as? [[Float]] {
print(floatArr)
} else {
print("failed")
}
This produces [[1.10000002, 2.0], [inf]]
in Swift 3, but fails
in Swift 4.
To summarize: Your code is fine.
- If you don't care about "loosing
precision" or overflows then there is no need to change anything. In Swift 4
you can write it as
Float(truncating: 0ドル)
to emphasize that the result might not be exactly identical to the given numbers. - If you care then you can use the new "exactly" initializers,
or the bridged cast
as? [[Float]]
in Swift 4.