如何优化电表读数图表数据的准备流程?
优化电表读数图表数据生成方案
针对你的需求,我们可以利用Swift标准库的高阶集合函数替代ForEach,直接基于ReadingET实体处理数据,跳过Consumption结构体的中转,以下是具体实现:
先修正重复定义的SeriesData
原代码中SeriesData存在重复的chartValues属性,这里调整为存储聚合后的读数数据:
struct SeriesData: Identifiable { var id: Int var chartLabel: String = "" // 存储聚合后的季度/月度/年度数据 var chartValues: [AggregatedReading] } // 替代原Consumption的轻量聚合结构体,直接基于ReadingET的计算结果 struct AggregatedReading: Identifiable { let id = UUID() var year: String var quarter: String? // 仅季度数据填充 var month: String? // 仅月度数据填充 var totalConsumption: Double var endDate: Date // 对应周期的结束日期 }
季度数据生成(满足所有要求)
使用filter筛选目标年份数据,Dictionary(grouping:by:)按季度分组,reduce求和,全程无手动ForEach遍历:
private func getQuarterlyConsumptionByYear(year: Int) -> [AggregatedReading] { let targetYear = String(year) // 1. 筛选目标年份的读数 let yearlyReadings = readings.filter { $0.readingYear == targetYear } // 2. 按季度分组 let groupedByQuarter = Dictionary(grouping: yearlyReadings, by: { $0.readingQuarter }) // 3. 定义季度与对应结束日期的配置(修正原代码中6月31日的错误) let quarterConfigs = [ ("Q1", "03", "31"), ("Q2", "06", "30"), ("Q3", "09", "30"), ("Q4", "12", "31") ] // 4. 生成聚合数据 return quarterConfigs.map { quarter, month, day in let quarterData = groupedByQuarter[quarter] ?? [] // 用reduce计算该季度总用电量 let totalConsumption = quarterData.reduce(0.0) { $0 + $1.readingConsumption } // 解析周期结束日期(假设你有Date的字符串解析扩展) let endDate = Date(fromString: "\(year)-\(month)-\(day)", format: .isoDate)! return AggregatedReading( year: targetYear, quarter: quarter, month: nil, totalConsumption: totalConsumption, endDate: endDate ) } }
月度/年度数据的类似实现
月度数据
private func getMonthlyConsumptionByYear(year: Int) -> [AggregatedReading] { let targetYear = String(year) let yearlyReadings = readings.filter { $0.readingYear == targetYear } let groupedByMonth = Dictionary(grouping: yearlyReadings, by: { $0.readingMonth }) // 生成1-12月的配置,动态获取每月最后一天避免硬编码错误 let monthConfigs = (1...12).map { month -> (String, String) in let monthStr = String(format: "%02d", month) let endDay = Calendar.current.range(of: .day, in: .month, for: DateComponents(year: year, month: month))?.count ?? 28 return (monthStr, String(endDay)) } return monthConfigs.map { monthStr, dayStr in let monthData = groupedByMonth[monthStr] ?? [] let totalConsumption = monthData.reduce(0.0) { $0 + $1.readingConsumption } let endDate = Date(fromString: "\(year)-\(monthStr)-\(dayStr)", format: .isoDate)! return AggregatedReading( year: targetYear, quarter: nil, month: monthStr, totalConsumption: totalConsumption, endDate: endDate ) } }
年度数据
private func getYearlyConsumption() -> [AggregatedReading] { // 按年份分组并排序 let groupedByYear = Dictionary(grouping: readings, by: { $0.readingYear }) .sorted { $0.key < $1.key } return groupedByYear.map { year, yearData in let totalConsumption = yearData.reduce(0.0) { $0 + $1.readingConsumption } let endDate = Date(fromString: "\(year)-12-31", format: .isoDate)! return AggregatedReading( year: year, quarter: nil, month: nil, totalConsumption: totalConsumption, endDate: endDate ) } }
方案满足的要求说明
- 避免ForEach:全程使用
filter、Dictionary(grouping:by:)、map、reduce等高阶函数,无手动遍历逻辑 - 利用便捷数组函数:依赖Swift标准库的集合操作API,代码更简洁易维护
- 直接使用ReadingET:所有计算均基于原始
ReadingET数组,无需通过Consumption结构体中转,仅用轻量的AggregatedReading存储聚合结果
内容的提问来源于stack exchange,提问作者Mrt
相关产品推荐
相关产品推荐

