I'm a little confused around flatMap (added to Swift 1.2)
Say I have an array of some optional type e.g.
let possibles:[Int?] = [nil, 1, 2, 3, nil, nil, 4, 5]
In Swift 1.1 I'd do a filter followed by a map like this:
let filtermap = possibles.filter({ return $0 != nil }).map({ return $0! })
// filtermap = [1, 2, 3, 4, 5]
I've been trying to do this using flatMap a couple ways:
var flatmap1 = possibles.flatMap({
return $0 == nil ? [] : [$0!]
})
and
var flatmap2:[Int] = possibles.flatMap({
if let exercise = $0 { return [exercise] }
return []
})
I prefer the last approach (because I don't have to do a forced unwrap $0!
... I'm terrified for these and avoid them at all costs) except that I need to specify the Array type.
Is there an alternative away that figures out the type by context, but doesn't have the forced unwrap?
Since Swift 4.1 you can use compactMap:
let possibles:[Int?] = [nil, 1, 2, 3, nil, nil, 4, 5]
let actuals = possibles.compactMap { $0 }
(Swift 4.1 replaced some overloads of flatMap with compactmap. If you are interested in more detail on this then see for example: https://useyourloaf.com/blog/replacing-flatmap-with-compactmap/ )
With Swift 2 b1, you can simply do
let possibles:[Int?] = [nil, 1, 2, 3, nil, nil, 4, 5]
let actuals = possibles.flatMap { $0 }
For earlier versions, you can shim this with the following extension:
extension Array {
func flatMap<U>(transform: Element -> U?) -> [U] {
var result = [U]()
result.reserveCapacity(self.count)
for item in map(transform) {
if let item = item {
result.append(item)
}
}
return result
}
}
One caveat (which is also true for Swift 2) is that you might need to explicitly type the return value of the transform:
let actuals = ["a", "1"].flatMap { str -> Int? in
if let int = str.toInt() {
return int
} else {
return nil
}
}
assert(actuals == [1])
For more info, see http://airspeedvelocity.net/2015/07/23/changes-to-the-swift-standard-library-in-2-0-betas-2-5/