Sort array por la distancia de la location actual

Estoy tratando de orderar una matriz por la distancia de la location actual. A continuación, primero verá el organizationObject , que contiene diferentes valores y luego tenemos ubicaciones que son una variedad de ubicaciones diferentes. la razón por la cual es una array es porque una organización puede tener múltiples ubicaciones. Luego, en mi ViewController, estoy creando un set de objects de testing y anexándolos a una matriz. Mi pregunta es ¿cómo puedo orderar este orgArray acuerdo con la distancia de orgArray ? Si hay varias ubicaciones en la matriz de location, debe tomar la más cercana.

OrganizationObject

 class OrganizationObject { var id: Int var name: String var image: UIImage var locations: [CLLocationCoordinate2D] init(id: Int, name: String, image: UIImage, locations: [CLLocationCoordinate2D]) { self.id = id self.name = name self.image = image self.locations = locations } } 

Anexando objects de testing a matriz. En viewDidLoad

 orgArray.append(OrganizationObject(id: 0, name: "Statens Museum For Kunst", image: UIImage(named: "statensmuseum.jpg")!, locations: [CLLocationCoordinate2D(latitude: 55.6888127, longitude: 12.578330300000061)])) orgArray.append(OrganizationObject(id: 0, name: "7 eleven", image: UIImage(named: "7eleven.jpg")!, locations: [CLLocationCoordinate2D(latitude: 58.334682, longitude: 8.231820900000002)])) orgArray.append(OrganizationObject(id: 0, name: "Kongens have", image: UIImage(named: "kongenshave.jpg")!, locations: [CLLocationCoordinate2D(latitude: 55.6852905, longitude:12.579845200000022)])) orgArray.append(OrganizationObject(id: 0, name: "Magasin du nord", image: UIImage(named: "magasin.jpg")!, locations: [CLLocationCoordinate2D(latitude: 50.6456604, longitude: 3.053486600000042), CLLocationCoordinate2D(latitude: 55.7835017, longitude: 12.370985799999971)])) 

Aquí hay una solución. Es un poco más complicado que una llamada directa a una function de sorting por un par de razones: en primer lugar la necesidad de encontrar la location más cercana para la organización, como se menciona en la pregunta, y en segundo lugar el hecho de que el cálculo de la haversina utilizado dentro de CLLocation 's distanceFromLocation: método puede ralentizar las cosas si se usa de manera ingenua.

Por esos motivos, he creado un object especial para hacer el orderamiento, de modo que puedo usar un dictionary miembro para memorizar los resultados de las llamadas a distanceFromLocation . Esto no hará una diferencia para los datos de testing, pero será importante si alguna vez necesita tratar con un gran set de lugares.

Como nota al margen, podría hacer las cosas un poco más simples si OrganizationObject almacenaba una CLLocation y no un CLLocationCoordinate , aunque este es un problema bastante menor.

Aquí está el código:

 class OrganizationSorter { var memoizedValues = [Int:CLLocationDistance]() private func shortestDistanceToOrganizationFromLocation(organization:OrganizationObject,location:CLLocation) -> CLLocationDistance? { let memoizedValue = memoizedValues[organization.id] //Check whether we've done this calculation before, if so return the result from last time if memoizedValue != nil { return memoizedValue } //There should probably be some code around here to check //that the organization object has at least one location //I'm assuming it does to simplify things var shortestDistance : CLLocationDistance? = nil let locations = organization.locations if locations.count > 0 { for coord in locations { let loc = CLLocation(latitude: coord.latitude, longitude: coord.longitude) let dist = loc.distanceFromLocation(location) if shortestDistance == nil || shortestDistance > dist { shortestDistance = dist } } } if shortestDistance != nil { memoizedValues[organization.id] = shortestDistance } return shortestDistance } func sortOrganizationsByDistanceFromLocation(orgArray:[OrganizationObject],location:CLLocation) -> [OrganizationObject] { let sortedArray = orgArray.sort { (a:OrganizationObject, b:OrganizationObject) -> Bool in let dist1 = self.shortestDistanceToOrganizationFromLocation(a, location: location) let dist2 = self.shortestDistanceToOrganizationFromLocation(b, location: location) return dist1 < dist2 } memoizedValues.removeAll() //reset memoized values in case object is used twice return sortedArray } } 

Lo he probado en sus datos de ejemplo, utilizando la location del Palacio de Christiansborg en Copenhague como un lugar de testing, y obtuve el siguiente orderamiento:

 Kongens have Statens Museum For Kunst Magasin du nord 7 eleven 

que parece coincidir con las coorderadas dadas, parece que las coorderadas más cercanas para Magasin du Nord están en algún lugar de una ciudad en las afueras de Copenhague (la otra en Lille), y 7 once en Suecia.

Aquí se describe cómo se usa la class (utilizando los datos de la testing de la pregunta original, con los valores de id en OrganizationObject modificados para que no sean todos 0 (de lo contrario, el código no funcionará).

 let location = CLLocation(latitude: 55.676251, longitude: 12.580570) //Christiansborg Palace, chosen since it is relatively near the other locations, to make it obvious whether results are sensible or not let orgSorter = OrganizationSorter() let sortedLocations = orgSorter.sortOrganizationsByDistanceFromLocation(orgArray, location: location) for org in orgArray { print(org.name) } print("\n") for org in sortedLocations { print(org.name) }