我经常需要计算数值数组的均值和标准差。所以我为数字类型编写了一个小协议和扩展,似乎可以工作。如果我这样做有什么问题,我只想得到反馈。具体来说,我想知道是否有更好的方法来检查类型是否可以转换为 Double 以避免需要 asDouble 变量和init(_:Double)
构造函数。
我知道允许算术的协议存在问题,但这似乎工作正常,并且使我免于将标准偏差函数放入需要它的类中。
protocol Numeric {
var asDouble: Double { get }
init(_: Double)
}
extension Int: Numeric {var asDouble: Double { get {return Double(self)}}}
extension Float: Numeric {var asDouble: Double { get {return Double(self)}}}
extension Double: Numeric {var asDouble: Double { get {return Double(self)}}}
extension CGFloat: Numeric {var asDouble: Double { get {return Double(self)}}}
extension Array where Element: Numeric {
var mean : Element { get { return Element(self.reduce(0, combine: {$0.asDouble + $1.asDouble}) / Double(self.count))}}
var sd : Element { get {
let mu = self.reduce(0, combine: {$0.asDouble + $1.asDouble}) / Double(self.count)
let variances = self.map{pow(($0.asDouble - mu), 2)}
return Element(sqrt(variances.mean))
}}
}
编辑:我知道获取[Int].mean
and有点毫无意义sd
,但我可能会在其他地方使用数字,所以这是为了保持一致性..
编辑:正如@Severin Pappadeux指出的那样,方差可以以一种避免数组三重传递的方式表示 - 均值然后映射然后均值。这是最终的标准偏差扩展
extension Array where Element: Numeric {
var sd : Element { get {
let sss = self.reduce((0.0, 0.0)){ return ($0.0 + $1.asDouble, $0.1 + ($1.asDouble * $1.asDouble))}
let n = Double(self.count)
return Element(sqrt(sss.1/n - (sss.0/n * sss.0/n)))
}}
}