derdida
derdida

Reputation: 14904

Count optional properties in Swift

Is it possible to count all properties who are not nil?

For example:

class test {
   var val1:Int?
   var val2:Int?
   var val3:Int?
   var val4:Int?
   var val5:Int?
}

var test = test()
test.val1 = 1
test.val2 = 2

How to find out that 2 properties are set? I could check for each one with (!= nil) - but is there an easier (and better) way?

Upvotes: 1

Views: 598

Answers (3)

Dániel Nagy
Dániel Nagy

Reputation: 12015

@Stuarts answer is good, but you have to know the properties of the class, and if you add another property to the class, you also have to modify your method. To avoid this problem, you can use reflection, like

Swift 1.2:

func numberOfOptionalProperties() -> Int {
    let mirror = reflect(self)
    var numberOfOptionalProperties = 0

    for index in 0..<mirror.count {

        if mirror[index].1.disposition == .Optional {
            ++numberOfOptionalProperties
        }
    }
    return numberOfOptionalProperties
}

Swift 2.0:

func numberOfOptionalProperties() -> Int {
   return Mirror(reflecting: self).children.reduce(0) {
        Mirror(reflecting: $1.value).displayStyle == .Optional ? $0 + 1 : $0
    }
}

Upvotes: 1

Stuart
Stuart

Reputation: 37053

You can do this manually, with a convenience method:

func numberOfNonNil() -> Int {
    let vals = [val1, val2, val3, val4, val5]
    return flatMap { $0 }.count
}

flatMap(_:) takes a closure that takes a single element of the array and returns an optional value (Element -> T?), and returns the result of applying that closure to each element of the array, with nil values ignored.


The only way to make this simpler would be to store your values as an array of optional Ints in the first place:

class Test {
    var vals: [Int?]
}

You can then still access each individual value using the array subscript notation (let val2 = vals[1]). You could then just use the second line in the convenience method above (filter then count) to get the number of non-nil values:

let nonNilCount = vals.flatMap { $0 }.count

If your values are of different types, this approach will still work if you cast the array to a type that encompasses all the different types:

class Test {
    var val1: Int?
    var val2: Double
    var val3: String
    var val4: MyRandomClass?

    func numberOfNonNil() -> Int {
        let vals = [val1, val2, val3, val4, val5] as [Any?]
        return flatMap { $0 }.count
    }
}

This works because all the values can be expressed as the type Any?.

Upvotes: 4

Firas
Firas

Reputation: 1752

I don't think there's a way to do this, but you can implement your own function like this:

class test {
    var val1:Int?
    var val2:Int?
    var val3:Int?
    var val4:Int?
    var val5:Int?

    func setVarsCount() -> Int {

        var setVariablesCount = 0

        if val1 != nil {
            setVariablesCount++
        }

        if val2 != nil {
            setVariablesCount++
        }

        if val3 != nil {
            setVariablesCount++
        }

        if val4 != nil {
            setVariablesCount++
        }

        if val5 != nil {
            setVariablesCount++
        }

        return setVariablesCount

    }

}

Upvotes: 1

Related Questions