Skip item when performing map in Swift?

2019-02-13 06:54发布

问题:

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?

回答1:

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