Swift 字典中元素的加权平均

Swift 字典中元素的加权平均,swift,swift4,Swift,Swift4,我有一本这样的字典: let tempDict = [100:2, 101:3, 102:4] 我需要找到字典中所有元素的加权平均值。所以我基本上想这样做 let keyMultValues = 100*2+101*3+102*4 let valTotal = 2+3+4 let final = keyMultValues/valTotal 我知道我可以循环浏览字典中的所有条目,但我想也许有一种更有效、更干净的方法来做到这一点 还有比这更好的方法吗 var keyMultValues = 0

我有一本这样的字典:

let tempDict = [100:2, 101:3, 102:4]
我需要找到字典中所有元素的加权平均值。所以我基本上想这样做

let keyMultValues = 100*2+101*3+102*4
let valTotal = 2+3+4
let final = keyMultValues/valTotal
我知道我可以循环浏览字典中的所有条目,但我想也许有一种更有效、更干净的方法来做到这一点

还有比这更好的方法吗

var keyMultValues = 0.0
tempDict.forEach({
    keyMultValues += $0.key*$0.value
})
let valTotal = reduce(priceDict.values, 0, +) //this part isn't working properly so any help you can give here would be great. I am using swift 4
这个怎么样

let keyValueProductsSum = dict.lazy.map(*).reduce(0, +)
let valueSum = dict.values.reduce(0, +)
let weightedAverage = keyValueProductsSum / valueSum
两项意见:

  • 如果你在做加权平均,你可能不想做整数计算。您可能需要浮点结果

  • 您可能希望避免将所有键与值相乘,然后将它们相加,再除以值之和而导致的溢出问题。您可能希望逐值执行该操作:

  • 因此:

    注意,这适用于原始值:

    let dictionary = [100:2, 101:3, 102:4]
    
    这也适用于较大的值,例如:

    let dictionary = [
        1_000_000_000: 20_000_000_000,
        1_000_000_001: 30_000_000_000,
        1_000_000_002: 40_000_000_000
    ]
    
    您从以下内容开始:

    var keyMultValues = 0
    tempDict.forEach({
       keyMultValues += $0.key*$0.value
    })
    let valTotal = reduce(priceDict.values, 0, +) //this part isn't working properly so any help you can give here would be great. I am using swift 4
    
    并询问:

    还有比这更好的方法吗

    var keyMultValues = 0.0
    tempDict.forEach({
        keyMultValues += $0.key*$0.value
    })
    let valTotal = reduce(priceDict.values, 0, +) //this part isn't working properly so any help you can give here would be great. I am using swift 4
    
    你的错误是你写的
    reduce
    不正确,应该是:

    tempDict.values.reduce(0, +)
    
    使用此修复程序,您的代码将生成正确的(使用整数算术)结果

    但是,您的代码对数据进行了两次传递,
    foreach
    reduce
    (编写本文时的其他答案进行两次或三次)。您自己的解决方案显示,您只需进行一次传递,只需修改它,使其遵循与用于
    keymultvalue
    相同的
    valTotal
    模式:

    var keyMultValues = 0
    var valTotal = 0
    tempDict.forEach({
       let val = $0.value // we are going to use it twice
       keyMultValues += $0.key * val
       valTotal += val
    })
    let final = keyMultValues / valTotal
    
    这只需对数据进行一次传递

    如果您的数字很大,您可能需要使用“边走边除算法”进行两次传递,如果您希望找到浮点加权平均值,则需要加入一些
    Double
    cast。@Rob的答案涵盖了这两个方面


    一次传递数据是否真的比两次更好(更快、更少的内存等等)?这只是一个练习!我添加此答案只是为了向您展示您最初的尝试离正确的解决方案有多近。

    让我看看。只是出于好奇,懒惰是为了什么?它的作用是什么?@NevinJethmalani它延迟了数组的生成,以包含
    map
    的结果。因为我们只需要迭代这些值,然后用
    .reduce(0,+)
    求和,所以没有理由让
    map
    浪费时间分配一个新的
    数组,并将所有结果复制到其中,只有我们在迭代数组一次后才能丢弃它。因此,如果我们去掉懒惰的数组,它是否仍会以同样的方式工作,但这只是一种更糟糕的方式?您可以简化映射,只需通过操作符
    map(*)
    @LeoDabus哦,是的
    reduce(priceDict.values,0,+)
    是Swift 1语法。在Swift 2中,一大堆无组织的自由函数被移动到Sequence等人的实例方法中!谢谢字典中只有几个值,所以我们不需要担心这些问题。但我会调查的!