Swift中Dictionary(grouping:by)按月份分组后如何实现有序排列
解决按月份分组后顺序混乱的问题
问题核心是Swift的Dictionary属于无序集合,通过Dictionary(grouping:by:)完成分组后,字典的键不会自动按时间顺序排列。要解决这个问题,需要将分组结果转换为有序结构,或者对字典键做排序处理后再使用。
方案1:转换为有序数组(推荐)
将分组后的字典转换成包含年月字符串和对应交易数组的有序元组数组,确保最终结果按时间顺序排列。
实现代码
var recentPayments: [(Date, SubscriptionItem)] = [] @State var transactionsByMonth: [String: [(Date, SubscriptionItem)]] = [:] // 新增有序变量用于展示 @State var sortedTransactionsByMonth: [(month: String, transactions: [(Date, SubscriptionItem)])] = [] func getPaymentsByMonths() { // 完成基础分组 transactionsByMonth = Dictionary(grouping: recentPayments) { payment in payment.0.formatted(.dateTime.year().month()) } // 对分组键排序:将年月字符串转回Date,保证时间顺序准确 sortedTransactionsByMonth = transactionsByMonth.sorted { first, second in let dateFormat = Date.FormatStyle().dateTime.year().month() guard let firstDate = Date(first.key, strategy: dateFormat), let secondDate = Date(second.key, strategy: dateFormat) else { return false } return firstDate < secondDate }.map { (month: $0.key, transactions: $0.value) } }
方案2:用可排序键分组后转字符串
先按(year: Int, month: Int)这种可直接排序的键完成分组,再转换为字符串键的字典,同时保留排序后的键顺序。
实现代码
var recentPayments: [(Date, SubscriptionItem)] = [] @State var transactionsByMonth: [String: [(Date, SubscriptionItem)]] = [:] // 可选:保存有序的年月键列表 @State var sortedMonthKeys: [String] = [] func getPaymentsByMonths() { // 按(year, month)分组,该键可直接排序 let groupedByYearMonth = Dictionary(grouping: recentPayments) { payment -> (Int, Int) in let components = Calendar.current.dateComponents([.year, .month], from: payment.0) return (components.year!, components.month!) } // 对(year, month)键排序 let sortedGroups = groupedByYearMonth.sorted { $0.key < $1.key } // 转换为目标格式的字典 transactionsByMonth = Dictionary(uniqueKeysWithValues: sortedGroups.map { key, value in let date = Calendar.current.date(from: DateComponents(year: key.0, month: key.1))! let monthString = date.formatted(.dateTime.year().month()) return (monthString, value) }) // 生成有序的年月键列表 sortedMonthKeys = sortedGroups.map { key in let date = Calendar.current.date(from: DateComponents(year: key.0, month: key.1))! return date.formatted(.dateTime.year().month()) } }
注意事项
- 不要直接对年月字符串排序:如果格式化字符串是
"Dec 2023"这类格式,字符串排序会出现"Jan 2024"排在"Dec 2023"之前的错误,必须通过原始Date或年/月数值来做排序依据。 - 使用
Calendar.current处理日期:确保日期组件的提取和转换符合用户所在时区的设置。
内容的提问来源于stack exchange,提问作者Cian B
相关产品推荐
相关产品推荐

