Search code examples
arraysswiftgenericsswift-extensions

Creating an extension to filter nils from an Array in Swift


I'm trying to write an extension to Array which will allow an array of optional T's to be transformed into an array of non-optional T's.

e.g. this could be written as a free function like this:

func removeAllNils(array: [T?]) -> [T] {
    return array
        .filter({ $0 != nil })   // remove nils, still a [T?]
        .map({ $0! })            // convert each element from a T? to a T
}

But, I can't get this to work as an extension. I'm trying to tell the compiler that the extension only applies to Arrays of optional values. This is what I have so far:

extension Array {
    func filterNils<U, T: Optional<U>>() -> [U] {
        return filter({ $0 != nil }).map({ $0! })
    }
}

(it doesn't compile!)


Solution

  • It's not possible to restrict the type defined for a generic struct or class - the array is designed to work with any type, so you cannot add a method that works for a subset of types. Type constraints can only be specified when declaring the generic type

    The only way to achieve what you need is by creating either a global function or a static method - in the latter case:

    extension Array {
        static func filterNils(_ array: [Element?]) -> [Element] {
            return array.filter { $0 != nil }.map { $0! }
        }
    }
    
    var array:[Int?] = [1, nil, 2, 3, nil]
    
    Array.filterNils(array)
    

    Or simply use compactMap (previously flatMap), which can be used to remove all nil values:

    [1, 2, nil, 4].compactMap { $0 } // Returns [1, 2, 4]