Swift字典排名优化:如何用更Swifty的方式实现同分同排名
优化Swift字典排名代码,更符合Swifty风格
嘿,你的排名功能逻辑没问题,但确实可以用Swift的函数式编程特性(比如reduce、map)来简化代码,去掉手动维护状态变量的部分,让代码更简洁优雅。
我给你两种优化方案,都能完美处理同分同排名的场景:
方案一:利用去重分数列表映射排名
这种方法逻辑直观,先提取所有唯一分数,再通过分数的位置确定排名:
首先我们需要给Sequence加一个简单的扩展来实现去重(保持原有顺序):
extension Sequence where Element: Equatable { func uniqued() -> [Element] { var seen = [Element]() return filter { element in guard !seen.contains(element) else { return false } seen.append(element) return true } } }
然后核心代码如下:
let dict: [String: Int] = ["team1":79,"team2":5, "team3":18, "team4":5, "team5": 82, "team6":1] // 1. 按分数从高到低排序团队 let sortedTeams = dict.sorted { $0.value > $1.value } // 2. 获取去重后的分数列表(保持降序) let uniqueScores = sortedTeams.map(\.value).uniqued() // 3. 为每个团队匹配对应的排名 let ranking = sortedTeams.map { team in // 找到分数在唯一列表中的位置,加1就是排名 let rank = uniqueScores.firstIndex(of: team.value)! + 1 return (team: team.key, rank: rank) } print(ranking) // 输出:[(team: "team5", rank: 1), (team: "team1", rank: 2), (team: "team3", rank: 3), (team: "team2", rank: 4), (team: "team4", rank: 4), (team: "team6", rank: 5)]
方案二:用reduce跟踪状态(无需扩展)
如果不想额外写扩展,可以用reduce来同时跟踪当前排名、上一个分数和结果列表,全程保持函数式风格:
let dict: [String: Int] = ["team1":79,"team2":5, "team3":18, "team4":5, "team5": 82, "team6":1] let ranking = dict.sorted { $0.value > $1.value } .reduce(into: (rankings: [(team: String, rank: Int)](), currentRank: 1, lastScore: Int?.none)) { accumulator, currentTeam in // 如果当前分数和上一个不同,更新排名为已添加元素的数量+1 if let lastScore = accumulator.lastScore, lastScore != currentTeam.value { accumulator.currentRank = accumulator.rankings.count + 1 } // 添加当前团队和排名到结果 accumulator.rankings.append((team: currentTeam.key, rank: accumulator.currentRank)) // 更新上一个分数 accumulator.lastScore = currentTeam.value }.rankings print(ranking) // 输出和预期完全一致
这两种方案都避免了手动循环和可变的pos变量,更符合Swift推崇的函数式、无副作用的编程风格,代码也更简洁易维护。
内容的提问来源于stack exchange,提问作者Simone Pistecchia
相关产品推荐
相关产品推荐

