iosarraysswiftcgpoint

Get the max and min values from an Array of CGPoints


We have an array of CGPoints:

let points = [(1234.0, 1053.0), (1241.0, 1111.0), (1152.0, 1043.0)]

What I'm trying to do is get the CGPoint with the highest x value and the one with the highest y value in the array. I will be using these points to create a CGRect:

extension CGRect {
    init(p1: CGPoint, p2: CGPoint) {
        self.init(x: min(p1.x, p2.x),
                  y: min(p1.y, p2.y),
                  width: abs(p1.x - p2.x),
                  height: abs(p1.y - p2.y))
    }
}

I know there a way to get max and min values in an array by doing something like this:

points.min()
points.max()

but these don't seem to work since its an array of CGPoints. Is it possible to get these values from the array?


Solution

  • You can map values to find the min and max in x and y coordinates like below. If you're not sure if points array contains any data, use guard statement to avoid force unwrapping:

    let xArray = points.map(\.x)
    let yArray = points.map(\.y)
    guard let minX = xArray.min(),
          let maxX = xArray.max(),
          let minY = yArray.min(),
          let maxY = yArray.max() else { return }
    

    And from there:

    let minPoint = CGPoint(x: minX, y: minY)
    let maxPoint = CGPoint(x: maxX, y: maxY)
    

    then you can modify your extension function because you already know which values are min and max:

    extension CGRect {
        init(minPoint: CGPoint, maxPoint: CGPoint) {
            self.init(x: minPoint.x,
                      y: minPoint.y,
                      width: maxPoint.x - minPoint.x,
                      height: maxPoint.y - minPoint.y)
        }
    }
    

    As Leo Dabus suggested in the comment below, you can do it all in one go inside failable initializer extension:

    extension CGRect {
        init?(points: [CGPoint]) {
            let xArray = points.map(\.x)
            let yArray = points.map(\.y)
            if  let minX = xArray.min(),
                let maxX = xArray.max(),
                let minY = yArray.min(),
                let maxY = yArray.max() {
    
                self.init(x: minX,
                          y: minY,
                          width: maxX - minX,
                          height: maxY - minY)
            } else {
                return nil
            }
        }
    }