Swift:数组map或reduce,用索引

时间:2016-01-17 19:04:30

标签: arrays swift filter mapping reduce

我有一个值数组[CGFloat]和天数[CGFloat],每个值都与之关联(时间也很重要,所以days数组是十进制值)。

每天都有0到n之间的值。 (通常小于5或6)

我想找到每天的平均值,所以在计算之后我想有一个数组[CGFloat]和一个天数[CGFloat],或两个组合的字典或数组[CGPoint]。我相当肯定这可以通过映射或简化或过滤功能完成,但我遇到了麻烦。 例如

第三天可能看起来像[2.45,2.75,2.9] 相关值[145.0,150.0,160.0]

我希望以[2] = 2.7结束 和值[2] = 151.7

[CGPoint(2.7, 151.7)] or [2.7 : 151.7]

有人可以提供指导吗?

一些代码:

let xValues : [CGFloat] = dates.map{round((CGFloat($0.timeIntervalSinceDate(dateZero))/(60*60*24))*100)/100}
let yValues : [CGFloat] = valueDoubles.map{CGFloat($0)}
//xValues and yValues are the same length
var dailyMeans = [CGFloat]()
var xVals = [CGFloat]()

let index = Int(ceil(xValues.last!))

for i in 0..<index{

    let thisDay = xValues.enumerate().filter{$0.element >= CGFloat(i) && $0.element < CGFloat(i+1)}
    if thisDay.count > 0{
        var sum : CGFloat = 0
        var day : CGFloat = 0
        for i in thisDay{
            sum += yValues[i.index]
            day += xValues[i.index]
        }
        dailyMeans.append(sum/CGFloat(thisDay.count))
        xVals.append(day/CGFloat(thisDay.count))
    }

}

以上代码有效,但也必须执行enumerate.filter函数values.count * days.last次。所以40天和160读数..像6500次。而且我已经在使用过多的处理能力了。有一个更好的方法吗?

编辑:忘记了一行代码,将索引定义为xValues.last

的上限

这已经被发现了1000次,所以我想我会用我的最终解决方案更新:

var daySets = [Int: [CGPoint]]()
// points is the full array of (x: dayTimeInDecimal, y: value)
for i in points {
    let day = Int(i.x)

    daySets[day] = (daySets[day] ?? []) + [i]
}

let meanPointsEachDay = daySets.map{ (key, value) -> CGPoint in
    let count = CGFloat(value.count)
    let sumPoint = value.reduce(CGPoint.zero, {CGPoint(x: $0.x + $1.x, y: $0.y + $1.y)})
    return CGPoint(x: sumPoint.x/count, y: sumPoint.y/count)
}

1 个答案:

答案 0 :(得分:2)

if let (day, value) = res[2] {
    print(day, value) // 2.7 151.666666666667
}

请注意,您的数据的每个元素在“计算”中仅处理一次,与“&#39;密钥”的大小无关。设定尺寸

使用Swift的Double而不是CGFloat!这也增加了速度: - )

最后你要找的是什么

Dim i as Integer  
JobName = NewJob.Value

If New_Job.JobYes.Value Then
strDir1 = "C:\QTR\" & JobName & " QTR"
strDir2 = "C:\QT\" & JobName & " QT"
strDir3 = "C:\EMAILS\" & JobName & " EMAILS"
strDir4 = "C:\DOCUMENTS\" & JobName & " DOCS"        

    For i = 1 To 4
        If Dir(strDir, vbDirectory) = "" Then
            MkDir strDir & i
        Else
        MsgBox "Directory exists."
    End If
    Next i
Else
End If