3
\$\begingroup\$

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?

\$\endgroup\$
4
\$\begingroup\$

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 as Double(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.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.