如何在Swift中对一组元组中的类似元组进行平均

时间:2016-07-22 01:45:48

标签: arrays swift tuples

我真的需要你的帮助。我有一组看起来像这样的元组:

[("07-21-2016", 5), ("07-21-2016", 1), ("07-21-2016", 2), ("07-21-2016", 3), ("07-21-2016", 4), ("07-21-2016", 5), ("07-20-2016", 6), ("07-20-2016", 5), ("07-19-2016", 5)]

我需要使用相同日期的所有元组并将它们平均化。所以最后它看起来像:

[("07-21-2016", 33.3), ("07-20-2016", 5.5), ("07-19-2016", 5)]

有谁知道怎么做?

2 个答案:

答案 0 :(得分:2)

let array = [("07-21-2016", 5), ("07-21-2016", 1), ("07-21-2016", 2), ("07-21-2016", 3), ("07-21-2016", 4), ("07-21-2016", 5), ("07-20-2016", 6), ("07-20-2016", 5), ("07-19-2016", 5)]

// Create dictionary to hold mapping of date to array of values    
var dict = [String: [Double]]()

// use forEach to add each value to the array for each key    
array.forEach {(date, num) in dict[date] = (dict[date] ?? []) + [Double(num)]}

// use map with reduce to find the average of each value and return a tuple
// containing the date and the average value    
let result = dict.map {(date, nums) in (date, nums.reduce(0, combine: +) / Double(nums.count))}

print(result)

输出:

[("07-20-2016", 5.5), ("07-19-2016", 5.0), ("07-21-2016", 3.3333333333333335)]

说明:

array.forEach {(date, num) in dict[date] = (dict[date] ?? []) + [Double(num)]}

forEach获取数组的每个元组,查找与dict[date]对应的值数组,并将新的num附加到该数组。如果dict[date]返回nil,那么这是我们第一次看到此密钥,因此请使用 nil coalescing operator ??返回一个空数组[]并将新值附加到该数据。

最后,dict的内容是:

["07-20-2016": [6.0, 5.0], "07-19-2016": [5.0], "07-21-2016": [5.0, 1.0, 2.0, 3.0, 4.0, 5.0]]
let result = dict.map {(date, nums) in (date, nums.reduce(0, combine: +) / Double(nums.count))}

map应用于字典时,它会占用每个(key, value)对,并根据该值创建新值。 map的最终结果是它返回的值的新数组。在这种情况下,每次map次迭代返回的值是一个包含date的元组以及与该日期相关的数字的平均值。

nums.reduce(0, combine: +)

这会对nums数组中的值求和。 reduce采用初始值(在这种情况下为0)和将为nums数组中的每个值计算的闭包。 reduce的每次迭代都会获取当前运行总计和nums中的下一个值并对它们求和。然后将该总和除以Double(nums.count)以产生平均值。最后,map返回(date, avg),产生最终结果。

答案 1 :(得分:0)

这是一种方式(使用字典整理数字):

 let dateValues = [("07-21-2016", 5), ("07-21-2016", 1), ("07-21-2016", 2), ("07-21-2016", 3), ("07-21-2016", 4), ("07-21-2016", 5), ("07-20-2016", 6), ("07-20-2016", 5), ("07-19-2016", 5)]

 var averages:[String:(Int,Int)] = [:]
 for (date,value) in dateValues
 {
    averages[date] = averages[date] ?? (0,0)
    averages[date] = (averages[date]!.0 + value, averages[date]!.1 + 1)
 }
 let averagePerDate = averages.map{($0,Float($1.0)/Float($1.1))}.sort{$0.0>$1.0}

 print(averagePerDate) 

 // [("07-21-2016", 3.33333325), ("07-20-2016", 5.5), ("07-19-2016", 5.0)]

使用集合更简洁:

 let dateList     = dateValues.reduce( Set<String>(), combine: { $0.union(Set([$1.0])) })
 let dateData     =   dateList.map{ date in return (date, dateValues.filter({$0.0==date}).map{$0.1}) }
 let dateCounts   =   dateData.map{ ($0, $1.reduce(0,combine:+), Float($1.count) ) }
 let dateAverages = dateCounts.map{ ($0, Float($1/$2) ) }.sort{$0.0>$1.0}

 print(dateAverages)