indexOfPointWithMinimalDistance()算法的优化实现探讨
优化CGPoint数组查找最近点索引的实现:简洁性与效率提升
针对CGPoint数组查找与目标点距离最小元素索引的需求,我们可以从函数式简洁性和执行效率两个维度进行优化,以下是具体方案:
一、简洁性优化:用函数式编程简化实现
原实现通常会用可变变量记录最小距离和索引,我们可以借助Swift的enumerated()和reduce()方法,用无副作用的函数式写法替代,代码更紧凑且可读性强:
extension Array where Element == CGPoint { func indexOfPointWithMinimalDistance(to target: CGPoint) -> Int? { guard !isEmpty else { return nil } return enumerated() .reduce((index: 0, distance: CGFloat.greatestFiniteMagnitude)) { currentState, nextItem in let currentDistance = hypot(nextItem.element.x - target.x, nextItem.element.y - target.y) return currentDistance < currentState.distance ? (nextItem.offset, currentDistance) : currentState } .index } }
优化说明:
- 用
enumerated()同时获取元素索引和值,避免手动维护索引变量 - 借助
reduce()累积遍历过程中的最小距离和对应索引,消除了可变状态(原代码中的minDistance和resultIndex) - 逻辑和原实现完全一致,当多个点距离相同时,返回第一个出现的索引
二、效率优化:避免不必要的开根号计算
原实现中使用hypot()计算欧氏距离,而hypot()内部会执行开根号操作——这是一个相对耗时的运算。由于我们只需要比较距离大小,完全可以用平方距离替代实际距离(平方的大小关系和原距离一致),省去开根号的开销,在数组元素较多时效率提升明显:
extension Array where Element == CGPoint { func indexOfPointWithMinimalDistance(to target: CGPoint) -> Int? { guard !isEmpty else { return nil } // 提前定义计算差值的闭包,避免重复写逻辑 let deltaX = { (point: CGPoint) -> CGFloat in point.x - target.x } let deltaY = { (point: CGPoint) -> CGFloat in point.y - target.y } return enumerated() .reduce((index: 0, squaredDistance: CGFloat.greatestFiniteMagnitude)) { currentState, nextItem in let sqDist = deltaX(nextItem.element) * deltaX(nextItem.element) + deltaY(nextItem.element) * deltaY(nextItem.element) return sqDist < currentState.squaredDistance ? (nextItem.offset, sqDist) : currentState } .index } }
额外效率提示:
如果你的CGPoint数组是有序的(比如按x坐标或y坐标排序),可以考虑用二分查找缩小遍历范围,但对于无序数组来说,线性遍历是最优复杂度(O(n)),无法再进一步降低时间复杂度。
内容的提问来源于stack exchange,提问作者andrewz
相关产品推荐
相关产品推荐

