How can I write this generic as a var instead of a func?

When an Array has an Element type that is an optional, I'd like to count the non-nil elems. Is there a way to do this with just a var? How can I say that Element is an Optional<T>, without introducing T via the generic func? Thanx.

extension Array {
    func someCount<T>() -> Int where Element == Optional<T> {
        self.reduce(0) { count, elem in count + (elem == nil ? 0 : 1) 
    }
}

Replies

I found the very clever ideas here, and could make it work…

https://stackoverflow.com/questions/25064644/how-to-determine-if-a-generic-is-an-optional-in-swift

https://stackoverflow.com/questions/28190631/creating-an-extension-to-filter-nils-from-an-array-in-swift/38548106#38548106

protocol OptionalType {
    associatedtype Wrapped
    func map<U>(_ f: (Wrapped) throws -> U) rethrows -> U?
}

extension Optional: OptionalType {}

extension Sequence where Iterator.Element: OptionalType {
    private func removeNils() -> [Iterator.Element.Wrapped] {
        var result: [Iterator.Element.Wrapped] = []
        for element in self {
            if let element = element.map({ $0 }) {
                result.append(element)
            }
        }
        return result
    }
    
    var total : Int {
        self.removeNils().count
    }

}

let ar : [Int?] = [1, 2, nil, 4]
print(ar.total)

Or specifically the Array extension:

protocol OptionalType {
    associatedtype Wrapped
    func map<U>(_ f: (Wrapped) throws -> U) rethrows -> U?
}

extension Optional: OptionalType {}

extension Array where Element: OptionalType {
    private func removeNils() -> [Element.Wrapped] {
        var result: [Element.Wrapped] = []
        for element in self {
            if let element = element.map({ $0 }) {
                result.append(element)
            }
        }
        return result
    }
    
    var total : Int {
        self.removeNils().count
    }

}


let ar : [Int?] = [1, 2, nil, 4]
print(ar.total)
  • Thanx - that is a clever sidestep in order to get a protocol for Optional other than "must be enum with cases none and some", but in practice I'll just keep typing my extra two parens after .someCount :-)

  • Yes, using func is much easier. But your question was a challenge to find a way to express it as a var. Good continuation, don't forget to close the thread. It may be of interest of others to see there was a solution tou the question, even though too complex for the benefit.

Add a Comment