Reputation: 69322
I have an array of nullable items which may or may not have any nil
s in it:
let source = [1, 2, 3] as [Int?]
// or
let source = [1, 2, nil] as [Int?]
I want to turn it into an [Int]?
with the values as Int
s if no items are nil
or nil
if any item is nil
.
What's the idiomatic way to do this?
Things I've tried:
// fails with: fatal error: can't unsafeBitCast between types of different sizes
let result = source as? [Int]
and:
func toNonNullable<T>(array: [T?]) -> [T]? {
if array.filter({$0 == nil}).count != 0 {
return nil;
}
return array.map({$0!})
}
// This works, but seems likey to be non-idiomatic (as well as being ineffecient).
let result = toNonNullable(source)
Upvotes: 0
Views: 1390
Reputation: 535766
Here's how I would write it:
let source = [1, 2, nil] as [Int?]
var result : [Int]? = {
for i in source {
if i == nil {
return nil
}
}
return source.map {$0!}
}()
But that doesn't really meet your "inefficient" consideration. Someone has to look through the array to see if it contains nil, so nothing is lost by looping and doing that; but the inefficiency is that we loop twice, because map
is a loop. If you really hate that, here's a way out:
var result : [Int]? = {
var temp = [Int]()
for i in source {
if let i = i {
temp.append(i)
} else {
return nil
}
}
return temp
}()
Lots of very idiomatic Swifties in those formulations, I think!
Upvotes: 3