jjatie jjatie - 4 months ago 26
Swift Question

Sample variation for an array of Int in Swift

Building on this question, I am trying to calculate the variance of an array of Int.

My extension looks like this so far:

extension Array where Element: Integer {
/// Returns the sum of all elements in the array
var total: Element {
return reduce(0, combine: +)
}
/// Returns the average of all elements in the array
var average: Double {
return isEmpty ? 0 : Double(total.hashValue) / Double(count)
}

/// Returns an array of the squared deviations from the mean
var squaredDeviations: [Double] {
let mean = average
return isEmpty ? 0 : map( { number in
let difference = Double(number) - mean
return pow(distance, 2)
})
}
}


Total and average work fine, but for squaredDifferences it appears that you must return the same type as the array when using
map
. Is there a way to get around this?

Update I was receiving the compiler error:


Result values in '? :" expression have mismatching types 'Int' and
'[ _ ]'


The problem was that I was returning 0 which is not an array of Doubles. Also I was not using number.hashValue, and therefor couldn't initialize the double.

Answer

The issue here is that you have two possible values that can be returned:

return isEmpty ? 0 : map( { number in
    let difference = Double(number) - mean
    return pow(distance, 2)
})

Lets break these conditional operator down into if/else:

if isEmpty {
    return 0 //inferred return type: Int
}
else {
    return map( { number in
        let difference = Double(number) - mean
        return pow(distance, 2)
    }) // inferred return type: [Double]
}

The two possible returns have different types.

Variance is the the average of the squared differences from the Mean. You forgot to do the averaging step. Try:

var squaredDeviations: Double {
    let mean = average
    return isEmpty ? 0.0 : self.map{ pow(Double($0) - mean, 2) }.average
}

On a side note: I would recommend against using computed properties to do expensive computations. It's presents a misleading API that doesn't make it clear that it's a slow, linear time, procedure. Here's how I would do this:

extension Array where Element: Integer {
    /// Returns the sum of all elements in the array
    func summed() -> Element {
        return self.reduce(0, combine: +)
    }

    /// Returns the average of all elements in the array
    var averaged() Double {
        return self.isEmpty ? 0 : Double(self.summed()) / Double(count)
    }

    /// Returns an array of the squared deviations from the mean
    func squaredDeviations() -> [Double] {
        let average = self.averaged()
        return isEmpty ? [] : map{ pow(Double($0) - average, 2)}
    }

    /// Returns the variance of the Array
    func variance() -> Double {
        return self.squaredDeviations().averaged()
    }
}
Comments