You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中如何将每日PriceData数组转换为月度数组(含数据缺失处理)

解决每日价格数据转月度数据(含日期缺失处理)

核心思路

  1. 先过滤无效日期数据并按时间排序,确保数据基础可靠
  2. 保留原始数据的首尾条目,保证时间范围的完整性
  3. 生成首尾日期之间的所有月份,对每个月份优先选取目标日期(如20日)的数据
  4. 若目标日期无数据,则选取当月最接近目标日期的条目作为替代
  5. 合并所有数据并去重排序,得到最终月度数据集

完整实现代码

首先添加日期处理工具和PriceData扩展:

import Foundation

// 假设你的PriceData定义如下
struct PriceData: Identifiable, Hashable { // 实现Hashable用于去重
    let id = UUID()
    let date: String
    let close: Double
}

private let dateFormatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd"
    formatter.locale = Locale(identifier: "en_US_POSIX")
    formatter.timeZone = TimeZone(secondsFromGMT: 0)
    return formatter
}()

extension PriceData {
    var dateValue: Date? {
        dateFormatter.date(from: date)
    }
}

然后实现核心转换函数:

func extractData(_ dataArray: [PriceData]) -> [PriceData] {
    // 过滤无效日期数据并按时间排序
    let validData = dataArray.filter { $0.dateValue != nil }
                             .sorted { $0.dateValue! < $1.dateValue! }
    
    guard validData.count >= 2 else { return validData }
    
    let firstData = validData.first!
    let lastData = validData.last!
    
    guard let startDate = firstData.dateValue, let endDate = lastData.dateValue else {
        return [firstData, lastData]
    }
    
    // 生成首尾日期之间的所有月份
    func monthsBetween(start: Date, end: Date) -> [Date] {
        guard let calendar = Calendar(identifier: .gregorian) else { return [] }
        var months: [Date] = []
        var currentMonth = calendar.date(byAdding: .month, value: 1, to: start)!
        while currentMonth < end {
            months.append(currentMonth)
            currentMonth = calendar.date(byAdding: .month, value: 1, to: currentMonth)!
        }
        return months
    }
    
    let middleMonths = monthsBetween(start: startDate, end: endDate)
    
    // 为指定月份选取最优数据(优先20日,无则取最接近的)
    func bestPriceDataForMonth(targetMonth: Date, from data: [PriceData]) -> PriceData? {
        guard let calendar = Calendar(identifier: .gregorian) else { return nil }
        let components = calendar.dateComponents([.year, .month], from: targetMonth)
        guard let startOfMonth = calendar.date(from: components),
              let endOfMonth = calendar.date(byAdding: DateComponents(month: 1, day: -1), to: startOfMonth) else {
            return nil
        }
        
        // 筛选当月所有有效数据
        let monthlyData = data.filter {
            guard let date = $0.dateValue else { return false }
            return date >= startOfMonth && date <= endOfMonth
        }
        
        guard !monthlyData.isEmpty else { return nil }
        
        // 优先查找当月20日的数据
        let targetDay = 20
        if let targetDate = calendar.date(bySetting: .day, value: targetDay, of: startOfMonth),
           let targetData = monthlyData.first(where: { $0.dateValue == targetDate }) {
            return targetData
        }
        
        // 无20日数据时,取最接近20日的条目
        let targetDate = calendar.date(bySetting: .day, value: targetDay, of: startOfMonth) ?? startOfMonth
        return monthlyData.min(by: {
            guard let d1 = $0.dateValue, let d2 = $1.dateValue else { return false }
            let diff1 = abs(d1.timeIntervalSince(targetDate))
            let diff2 = abs(d2.timeIntervalSince(targetDate))
            return diff1 < diff2
        })
    }
    
    // 收集中间月份的数据
    var middleData: [PriceData] = []
    for month in middleMonths {
        if let data = bestPriceDataForMonth(targetMonth: month, from: validData) {
            middleData.append(data)
        }
    }
    
    // 合并、去重并排序
    let allData = [firstData] + middleData + [lastData]
    let uniqueData = Array(Set(allData))
                       .sorted { $0.dateValue! < $1.dateValue! }
    
    return uniqueData
}

可调整的策略

  • 如果遇到整月无数据的极端情况,可以在bestPriceDataForMonth函数中添加逻辑,比如返回上一个月的最后一条数据,或者跳过该月
  • 可以替换选取规则:比如不取最接近20日的,而是取当月最后一条可用数据,只需修改bestPriceDataForMonth中的返回逻辑为monthlyData.last即可
  • 目标日期可自定义(比如改为每月15日),只需修改targetDay的值

内容的提问来源于stack exchange,提问作者SPR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 03:05:53