Search code examples
arraysswiftoption-typexcode6.1

Unwrap Sparse Array in Swift


I'd like to write an extension for Array which safely returns an unwrapped version of itself.

I can do it with a generic method like so:

func unwrapElements<T>(array: [T?]) -> [T] {
    let filtered: [T?] = array.filter{ $0 != nil }
    let unwrapped: [T] = filtered.map { $0! }
    return unwrapped
}

And I can call it like this:

let sparseNames: [String?] = ["alice", "bob", nil, "doug", nil, nil, "george", "hubert"]
let names: [String] = unwrapElements(sparseNames)

where names ends up being ["alice", "bob", "doug", "george", "hubert"] and is safe to iterate and work with each element.

However, I want to call it like this:

let names = sparseNames.unwrapElements()

I've seen a few similar questions (like this one) but they don't address how to create the method as an extension.


(this is tagged with Xcode6.1 to denote the version of Swift I'm using)


Note: Swift 1.2 Beta 3 has introduced the flatMap function which helps with optionally chaining arrays. See this excellent blog post here


Solution

  • You can't do this right now in Swift. To add that function as an extension to Array, you'd have to mark somehow that it's only callable with certain kinds of arrays: those with optional values as the subtype. Unfortunately, you can't further specialize a generic type, so global functions are the only way possible.

    This is the same reason Array has a sort method that takes a comparison function as a parameter, but it doesn't have a sort that "just works" if the array is full of Comparable members - to get that kind of function, you have to look at the top-level sort:

    func sort<T : Comparable>(inout array: [T])