让我的函数计算数组 Swift 的平均值

Posted

技术标签:

【中文标题】让我的函数计算数组 Swift 的平均值【英文标题】:Making my function calculate average of array Swift 【发布时间】:2015-04-02 00:19:23 【问题描述】:

我希望我的函数计算我的 Double 类型数组的平均值。该数组称为“投票”。目前,我有 10 个号码。

当我调用average function 来获取数组投票的平均值时,它不起作用。

这是我的代码:

var votes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

func average(nums: Double...) -> Double 
    var total = 0.0
    for vote in votes 
        total += vote
    
    let votesTotal = Double(votes.count)
    var average = total/votesTotal
    return average


average[votes]

我如何在这里调用平均值以获得平均值?

【问题讨论】:

平均(投票)。将其声明为 average(nums: [Double]) 并确保 votes 数组是 [Double]。现在它是一个 [Int] 【参考方案1】:

您应该使用reduce 方法对您的序列元素求和,如下所示:

Xcode Xcode 10.2+ • Swift 5 或更高版本

extension Sequence where Element: AdditiveArithmetic 
    /// Returns the total sum of all elements in the sequence
    func sum() -> Element  reduce(.zero, +) 


extension Collection where Element: BinaryInteger 
    /// Returns the average of all elements in the array
    func average() -> Element  isEmpty ? .zero : sum() / Element(count) 
    /// Returns the average of all elements in the array as Floating Point type
    func average<T: FloatingPoint>() -> T  isEmpty ? .zero : T(sum()) / T(count) 


extension Collection where Element: BinaryFloatingPoint 
    /// Returns the average of all elements in the array
    func average() -> Element  isEmpty ? .zero : sum() / Element(count) 


let votes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let votesTotal = votes.sum()                       // 55
let votesAverage = votes.average()                 // 5
let votesDoubleAverage: Double = votes.average()   // 5.5

如果您需要使用Decimal 类型,它的总和已经被AdditiveArithmetic 协议扩展方法覆盖,因此您只需要实现平均:

extension Collection where Element == Decimal 
    func average() -> Decimal  isEmpty ? .zero : sum() / Decimal(count) 



如果您需要对自定义结构的某个属性求和,我们可以扩展 Sequence 并创建一个以 KeyPath 作为参数的方法来计算其总和:

extension Sequence  
    func sum<T: AdditiveArithmetic>(_ predicate: (Element) -> T) -> T 
        reduce(.zero)  $0 + predicate($1) 
    


用法:

struct User 
    let name: String
    let age: Int


let users: [User] = [
    .init(name: "Steve", age: 45),
    .init(name: "Tim", age: 50)]

let ageSum = users.sum(\.age) // 95

并扩展集合以计算其平均值:

extension Collection 
    func average<T: BinaryInteger>(_ predicate: (Element) -> T) -> T 
        sum(predicate) / T(count)
    
    func average<T: BinaryInteger, F: BinaryFloatingPoint>(_ predicate: (Element) -> T) -> F 
        F(sum(predicate)) / F(count)
    
    func average<T: BinaryFloatingPoint>(_ predicate: (Element) -> T) -> T 
        sum(predicate) / T(count)
    
    func average(_ predicate: (Element) -> Decimal) -> Decimal 
        sum(predicate) / Decimal(count)
    


用法:

let ageAvg = users.average(\.age)                 // 47
let ageAvgDouble: Double = users.average(\.age)   // 47.5

【讨论】:

在 Swift 2 中,我得到“[Double]”类型的值没有成员“IntegerLiteralType” 可以对Decimal的数组执行此操作吗?代码extension Array where Element: Decimals 抛出错误 属性应在 O(1) 中工作,否则应在适当的注释中注明。在totalaverage 的情况下,我会使用方法而不是计算属性。请在此处查看一般约定中的第一条规则:swift.org/documentation/api-design-guidelines @Yoav 你说得有道理,'reduce' 确实在 O(n) 复杂度下运行,但我认为大多数开发人员会期望这些常见操作会被属性公开。方法和属性之间的不匹配将是更严重的罪过。请记住,它们是约定,而不是规则。【参考方案2】:

你的代码有一些错误:

//You have to set the array-type to Double. Because otherwise Swift thinks that you need an Int-array
var votes:[Double] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

func average(nums: [Double]) -> Double 

    var total = 0.0
    //use the parameter-array instead of the global variable votes
    for vote in nums
        total += Double(vote)
    

    let votesTotal = Double(nums.count)
    var average = total/votesTotal
    return average


var theAverage = average(votes)

【讨论】:

【参考方案3】:

一个小班轮,使用用 Swift 翻译的老式 Objective-C KVC:

let average = (votes as NSArray).value(forKeyPath: "@avg.floatValue")

你也可以求和:

let sum = (votes as NSArray).value(forKeyPath: "@sum.floatValue")

更多关于这个早已被遗忘的宝石:https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/KeyValueCoding/CollectionOperators.html

【讨论】:

【参考方案4】:

如果需要,使用过滤器进行简单平均(Swift 4.2):

let items: [Double] = [0,10,15]
func average(nums: [Double]) -> Double 
    let sum = nums.reduce((total: 0, elements: 0))  (sum, item) -> (total: Double, elements: Double) in
        var result = sum
        if item > 0  // example for filter
            result.total += item
            result.elements += 1
        

        return result
    

    return sum.elements > 0 ? sum.total / sum.elements : 0

let theAvarage = average(nums: items)

【讨论】:

【参考方案5】:

斯威夫特 4.2

纯粹的优雅简约,我喜欢:

// 1. Calls #3
func average <T> (_ values: T...) -> T where T: FloatingPoint

    return sum(values) / T(values.count)

在我们做这件事的同时,其他不错的基于reduce 的操作:

// 2. Unnecessary, but I appreciate variadic params. Also calls #3.
func sum <T> (_ values: T...) -> T where T: FloatingPoint

    return sum(values)


// 3.
func sum <T> (_ values: [T]) -> T where T: FloatingPoint

    return values.reduce(0, +)

图片来源:Adrian Houdart 的 MathKit,基本没有变化。


可爱的更新:

我在The Swift Programming Language找到了以下内容:

以下示例计算任意长度数字列表的算术平均值(也称为平均值):

func arithmeticMean(_ numbers: Double...) -> Double 
   var total: Double = 0
   for number in numbers 
       total += number
   
   return total / Double(numbers.count)

arithmeticMean(1, 2, 3, 4, 5)
// returns 3.0, which is the arithmetic mean of these five numbers
arithmeticMean(3, 8.25, 18.75)
// returns 10.0, which is the arithmetic mean of these three numbers

【讨论】:

【参考方案6】:

我有一组在更新函数中创建的信号,为了获得移动平均线,我使用这个函数计算由移动平均线周期定义的窗口内的平均值。由于我的目标是组装一组包含平均值的新信号,因此我将丢弃原始集合中的信号。对于那些希望在更新函数中使用移动平均线的人来说,这是一个很好的解决方案,例如在 SKScene 中。

func movingAvarage(_ period: Int) -> Double? 
  if signalSet.count >= period 
   let window = signalSet.suffix(period)
   let mean = (window.reduce(0, +)) / Double(period)
   signalSet = signalSet.dropLast(period)
   return mean
  
  return nil

【讨论】:

以上是关于让我的函数计算数组 Swift 的平均值的主要内容,如果未能解决你的问题,请参考以下文章

函数Average是啥意思

C语言试题五之计算并输出给定数组(长度为9)中每相邻两个元素之平均值的平方根之和

C++:数组作为函数形式参数让我出错

请用c语言编写一个函数fun功能是:计算n门课程的平均分,计算结果作为函数值返回

c++中 求 平均值是哪个函数

在 SQL Server 2008 R2 中计算平均值的窗口函数