Search code examples
swiftalgorithmcore-graphics

Better implementation of indexOfPointWithMinimalDistance()


Can this algorithm be improved upon, either in brevity (for example using functional programming) or efficiency?

import CoreGraphics 

extension Array where Element == CGPoint {
    
    func indexOfPointWithMinimalDistance(to: CGPoint) -> Int? {
        guard count > 0 else { return nil }
        var minimalDistance : CGFloat!
        var minimalIndex : Int = 0
        for i in 0..<count {
            let d = self[i].distance(to: to)
            if minimalDistance == nil || d < minimalDistance {
                minimalDistance = d
                minimalIndex = i
            }
        }
        return minimalIndex
    }
}

extension CGPoint {
    func distance(to: CGPoint) -> CGFloat { (to-self).length }
    var length : CGFloat { sqrt(x * x + y * y) }
}

func - (left: CGPoint, right: CGPoint) -> CGPoint {
    return CGPoint(x: left.x - right.x, y: left.y - right.y)
}


Solution

  • You could avoid calculating the sqrt( ) because you do not need the value you just want to compare it <.

    You could also simpify minimalDistanceSquare == nil || d < minimalDistanceSquare by assigning a impossible big value to minimalDistanceSquare during initalization. That would simplify your condition to d < minimalDistanceSquare

    import CoreGraphics 
    
    extension Array where Element == CGPoint {
    
    
    
     func indexOfPointWithMinimalDistance(to: CGPoint) -> Int? {
            guard count > 0 else { return nil }
            var minimalDistanceSquare : CGFloat = CGFloat.infinity
            var minimalIndex : Int = 0
            for i in 0..<count {
                let d = self[i].distanceSquare(to: to)
                if d < minimalDistanceSquare {
                    minimalDistanceSquare = d
                    minimalIndex = i
                }
            }
            return minimalIndex
        }
    }
    
    extension CGPoint {
        func distanceSquare(to: CGPoint) -> CGFloat { (to-self).length }
        var length : CGFloat {x * x + y * y}
    }
    
    func - (left: CGPoint, right: CGPoint) -> CGPoint {
        return CGPoint(x: left.x - right.x, y: left.y - right.y)
    }