Swift按日期分组字典数据出现重复值,如何修复?
解决加密货币按日期分组时的重复值问题
问题回顾
你有一组以时间戳为键的加密货币交易数据:
[1549424985: ["amount": "10.0", "symbol": "XRP"], 1546531017: ["amount": "1.0", "symbol": "ETH"], 1549424153: ["amount": "50.0", "symbol": "EOS"], 1546531031: ["amount": "200.0", "symbol": "XRP"]]
尝试用以下代码按日期分组后,结果出现了重复的币种条目:
typealias CryptoTuple = (symbol: String, amount: Double) var cryptosPerDay = [String: [CryptoTuple]]() var prev = "" groupedData.keys.sorted(by: <).forEach( { key in let date = parseToDateString(key) if let buy = groupedData[key], let symbol = buy["symbol"], let amountStr = buy["amount"], let amount = Double(amountStr) { if prev != date { cryptosPerDay[date] = [(symbol, amount)] if let old = cryptosPerDay[prev] { cryptosPerDay[date]?.append(contentsOf: old) } prev = date } else { cryptosPerDay[date]?.append((symbol, amount)) } } })
输出结果:
["2019-02-06": [(symbol: "EOS", amount: 50.0), (symbol: "ETH", amount: 1.0), (symbol: "XRP", amount: 200.0), (symbol: "XRP", amount: 10.0)], "2019-01-03": [(symbol: "ETH", amount: 1.0), (symbol: "XRP", amount: 200.0)]]
问题原因
你的核心逻辑错在日期切换时的处理:每当进入新的日期,你直接把前一天的所有交易条目追加到了当天的列表里,而不是合并同币种的金额。比如2019-02-06的条目里,ETH和XRP的旧记录(来自2019-01-03)被直接加了进去,和当天的新交易混在一起,导致同一币种出现多条记录。
修复方案
根据你的需求,分两种场景给出解决方案:
场景1:累计历史金额(每个日期显示截至当天的各币种总金额)
我们可以维护一个字典追踪当前各币种的累计余额,处理每笔交易后更新余额,再将当前的余额状态存入对应日期:
typealias CryptoTuple = (symbol: String, amount: Double) var cryptosPerDay = [String: [CryptoTuple]]() // 追踪当前各币种的累计金额 var currentBalances = [String: Double]() // 先按时间戳升序排序所有交易,保证处理顺序正确 let sortedKeys = groupedData.keys.sorted(by: <) for key in sortedKeys { let date = parseToDateString(key) guard let buy = groupedData[key], let symbol = buy["symbol"], let amountStr = buy["amount"], let amount = Double(amountStr) else { continue } // 更新当前币种的累计金额 currentBalances[symbol] = (currentBalances[symbol] ?? 0) + amount // 将当前所有币种的累计金额转为Tuple列表,存入对应日期 let dailyBalances = currentBalances.map { (symbol: $0.key, amount: $0.value) } cryptosPerDay[date] = dailyBalances }
运行后输出:
["2019-01-03": [(symbol: "ETH", amount: 1.0), (symbol: "XRP", amount: 200.0)], "2019-02-06": [(symbol: "EOS", amount: 50.0), (symbol: "ETH", amount: 1.0), (symbol: "XRP", amount: 210.0)]]
每个日期下的币种唯一,金额是截至当天的累计总和,完全消除重复。
场景2:仅保留当日交易(合并当天同币种的金额,不累计历史)
如果你的需求是每个日期只展示当天的交易,且当天同币种合并金额,可以先按日期分组原始交易,再对每个日期内的交易按币种求和:
typealias CryptoTuple = (symbol: String, amount: Double) var cryptosPerDay = [String: [CryptoTuple]]() // 第一步:按日期分组所有当日交易 var dailyTransactions = [String: [(symbol: String, amount: Double)]]() for key in groupedData.keys { let date = parseToDateString(key) guard let buy = groupedData[key], let symbol = buy["symbol"], let amountStr = buy["amount"], let amount = Double(amountStr) else { continue } // 用default参数自动初始化空数组 dailyTransactions[date, default: []].append((symbol, amount)) } // 第二步:对每个日期内的交易按币种求和 for (date, transactions) in dailyTransactions { var dailySum = [String: Double]() for (symbol, amount) in transactions { dailySum[symbol] = (dailySum[symbol] ?? 0) + amount } cryptosPerDay[date] = dailySum.map { (symbol: $0.key, amount: $0.value) } }
运行后输出:
["2019-01-03": [(symbol: "ETH", amount: 1.0), (symbol: "XRP", amount: 200.0)], "2019-02-06": [(symbol: "EOS", amount: 50.0), (symbol: "XRP", amount: 10.0)]]
总结
两种方案分别对应不同的业务需求,你可以根据实际需要选择。核心思路都是按币种进行金额合并,而不是简单叠加历史条目,这样就能避免重复值的出现。
内容的提问来源于stack exchange,提问作者Bogdan Bogdanov
相关产品推荐
相关产品推荐

