Swift中结合字典的Repeat-While循环实现输入向下匹配最近键问题排查
问题原因
- repeat-while循环逻辑完全颠倒:你设置的循环继续条件是
correctInput == true,但你的需求是没找到匹配键的时候继续循环,同时你在循环体内第一遍执行就直接return input,不管有没有匹配到都直接返回,所以循环永远只会执行一次 checkKey函数逻辑错误:你传入了score参数但实际判断用的是全局变量input,参数没有起到任何作用- Double精度问题:逐次减0.1的操作会导致浮点数精度丢失,比如运算后可能出现
12.4000000000001这类值,永远无法和字典里的12.4匹配成功 - 执行效率低:逐次递减匹配的时间复杂度很高,如果输入值和目标匹配值差距很大,会浪费大量算力
修复方案
更稳妥的实现方式是先把字典的所有键做降序排序,直接遍历一次排序后的键,找到第一个小于等于输入值的键即可,完全不需要循环递减:
struct FitnessScore { static let powerThrow = [ 12.50: 100, 12.40: 99, 12.20: 98, 12.10: 97, 11.90: 96, 11.80: 95, 11.60: 94, 11.50: 93, 11.30: 92, 11.20: 91, 11.00: 90, 10.90: 89, 10.70: 88, 10.60: 87, 10.40: 86, 10.30: 85, 10.10: 84, 10.00: 83, 9.80: 82 ] } let dict = FitnessScore.powerThrow let input = 19.30 // 先对所有键做降序排序 let sortedKeys = dict.keys.sorted(by: >) var finalInput: Double? // 遍历找第一个小于等于输入值的键 for key in sortedKeys { if key <= input { finalInput = key break } } if let final = finalInput { print("your input score rounded down to \(final), corresponding score is \(dict[final]!)") } else { print("input value is lower than all available keys") }
如果你一定要保留repeat-while的写法,修复后的代码如下:
let dict = FitnessScore.powerThrow var input = 19.30 var correctInput = false func checkKey(score: Double) -> Bool { for (key, _) in dict { // 修复为用传入的score做判断,同时加精度容错 if abs(key - score) < 0.001 { return true } } return false } func getFinalInput() -> Double { // 先判断初始值是否匹配 correctInput = checkKey(score: input) repeat { if !correctInput { input -= 0.1 correctInput = checkKey(score: input) print("this is the new input value: \(input)") print("this is the new condition: \(correctInput)") } } while !correctInput // 没找到就继续循环 return input } print("your input score rounded down to \(getFinalInput())")
执行结果
输入19.30时,输出的匹配值为12.5,对应分数100,符合向下取最接近匹配键的需求。
内容的提问来源于stack exchange,提问作者cbear84
相关产品推荐
相关产品推荐

