Swift用reduce和计算增量平均值

时间:2015-11-21 10:33:35

标签: swift average

建议逐步计算平均值 下面的代码是我发现计算增量平均值的最佳方法,以便将它用于大数字和/或大数组

以下是给这个数组加倍的例子

let values = [14.0,12.0, 23.4,37.5,11.46]

var index = 1

let avg = values.reduce(0.0) { return $0 + ( $1 - $0 ) / Double(index++) }
平均值为19.672。它有效。

从您的角度来看,这是否正确?

有没有办法通过以下方式实现这一目标:

let avg = values.averageIncr()

我不喜欢的是我必须使用和索引?

[更新]

更进一步,感谢@Martin R贡献

protocol NumericType:Equatable {
    func +(lhs: Self, rhs: Self) -> Self
    func -(lhs: Self, rhs: Self) -> Self
    func /(lhs: Self, rhs: Self) -> Self
    init(_ value : Int)
}

extension Double : NumericType { }

extension Array where Element : NumericType {
    mutating func avg_inc_adding( element: Element, var startAvg:Element? = Element(0)  ) throws -> Element{
        if count > 0 && startAvg! == Element(0) {
            startAvg = self.avg_inc()
        }
        append(element)
        return startAvg! + (element - startAvg!) / Element(self.count - 1)
    }
    func avg_inc() -> Element {
        return enumerate().reduce(Element(0)) { $0 + ( $1.1 - $0 ) / Element($1.0 + 1) }
    }
}
通过这种方式,我可以做类似的事情:

var average:Double = values.avg_inc()
do {
    average = try values.avg_inc_adding(34.6,startAvg: z)
}catch {

}

符合我的需要,我希望与其他人合作。

1 个答案:

答案 0 :(得分:3)

您可以获得相同的结果,而无需使用"外部变量" 与

let avg = values.enumerate().reduce(0.0) { $0 + ( $1.1 - $0 ) / Double($1.0 + 1) }

因为enumerate()返回一系列索引/元素对。

实现它作为扩展方法有点复杂但是 可能的:

protocol NumericType {
    func +(lhs: Self, rhs: Self) -> Self
    func -(lhs: Self, rhs: Self) -> Self
    func /(lhs: Self, rhs: Self) -> Self
    init(_ value : Int)
}

extension Double : NumericType { }

extension Array where Element : NumericType {
    func averageIncr() -> Element {
        return enumerate().reduce(Element(0)) { $0 + ( $1.1 - $0 ) / Element($1.0 + 1) }
    }
}

let avg = values.averageIncr()

Element扩展程序中的Array类型只能限制为 协议,而不是类型。与例如类似What protocol should be adopted by a Type for a generic function to take any number type as an argument in Swift?How can we create a generic Array Extension that sums Number types in Swift?,你必须定义一个 协议,其中包含计算中所需的所有方法。

限制Element: FloatingPointType是不够的,因为 FloatingPointType协议没有定义任何算术运算(+, - ,/)。

Swift 3的更新:从Swift 3 / Xcode 8开始,浮点数 类型符合FloatPoint协议并定义 算术运算(+, - ,/)。因此,自定义协议是 不再需要:

extension Array where Element: FloatingPoint {
    func averageIncr() -> Element {
        return enumerated().reduce(Element(0)) { $0 + ( $1.1 - $0 ) / Element($1.0 + 1) }
    }
}