Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Skip item when performing map in Swift?

I'm applying a map to a dictionary that has a try in it. I'd like to skip the iteration if the mapped item is invalid.

For example:

func doSomething<T: MyType>() -> [T]
    dictionaries.map({
        try? anotherFunc($0) // Want to keep non-optionals in array, how to skip?
    })
}

In the above sample, if anotherFunc returns nil, how to escape the current iteration and move on to the next? That way, it would not contain the items that are nil. Is this possible?

like image 676
TruMan1 Avatar asked Mar 29 '16 19:03

TruMan1


1 Answers

Just replace map() by flatMap():

extension SequenceType {
    /// Returns an `Array` containing the non-nil results of mapping
    /// `transform` over `self`.
    ///
    /// - Complexity: O(*M* + *N*), where *M* is the length of `self`
    ///   and *N* is the length of the result.
    @warn_unused_result
    public func flatMap<T>(@noescape transform: (Self.Generator.Element) throws -> T?) rethrows -> [T]
}

try? ... returns nil if the call throws an error, so those elements will be omitted in the result.

A self-contained example just for demonstration purposes:

enum MyError : ErrorType {
    case DivisionByZeroError
}

func inverse(x : Double) throws -> Double {
    guard x != 0 else {
        throw MyError.DivisionByZeroError
    }
    return 1.0/x
}

let values = [ 1.0, 2.0, 0.0, 4.0 ]
let result = values.flatMap {
    try? inverse($0)
}
print(result) // [1.0, 0.5, 0.25]

For Swift 3, replace ErrorType by Error.

For Swift 4 use compactMap

like image 183
Martin R Avatar answered Oct 08 '22 06:10

Martin R