Сортировка массива по расстоянию от текущего местоположения

Я пытаюсь сортировать массив на расстоянии от текущего местоположения. Ниже в первую очередь вы видите объект organizationObject , который содержит разные значения, а затем у нас есть местоположения, которые представляют собой массив разных местоположений. причина, по которой это array состоит в том, что организация может иметь несколько местоположений. Затем в моем ViewController я создаю набор тестовых объектов и добавляю к массиву. Мой вопрос в том, как я могу сортировать этот orgArray соответствии с расстояниемFromLocation? Если в массиве местоположений имеется несколько местоположений, он должен быть самым близким.

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 } } 

Добавление тестовых объектов в массив. В представленииDidLoad

 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)])) 

Вот решение. Это немного сложнее, чем простой вызов функции сортировки по нескольким причинам: во-первых, необходимо найти ближайшее место для организации, как упоминалось в вопросе, а во-вторых, тот факт, что расчет haversine, используемый внутри CLLocation distanceFromLocation: метод может замедлять работу вниз, если используется наивно.

По этим причинам я создал специальный объект для сортировки, чтобы я мог использовать словарь-член для memoize результатов вызовов distanceFromLocation . Это не повлияет на данные теста, но будет иметь значение, если вам когда-либо понадобится иметь дело с большим количеством мест.

В качестве побочного примечания – это может сделать вещи немного проще, если OrganizationObject сохранил CLLocation а не CLLocationCoordinate хотя это довольно незначительная проблема.

Вот код:

 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 } } 

Я протестировал его на ваших примерах данных, используя расположение дворца Christiansborg в Копенгагене в качестве тестового места и получил следующий заказ:

 Kongens have Statens Museum For Kunst Magasin du nord 7 eleven 

который, похоже, соответствует указанным координатам – похоже, что ближайшие уголки для Magasin du Nord находятся где-то в городе на окраине Копенгагена (другой в Лилле?), а 7 одиннадцать – в Швеции.

Вот как используется класс (используя тестовые данные из исходного вопроса, при этом значения id элементе OrganizationObject изменены, поэтому они не все 0 (иначе код не будет работать).

 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) } 
  • Цель C: Сортировка двухмерного массива
  • iOS: сортировка NSArray для упаковки NSValue CGPoint
  • Сортировка NSFetchedResultsController по NULL NSDates
  • Сортировка NSMutableArray с настраиваемыми объектами другим NSMutableArray
  • Основные данные, метод «сортировка по временному свойству»
  • iOS: как найти позицию вставки в отсортированном NSMutableArray
  • Сортировка контактов на основе недавно использованных / наиболее часто используемых / срочных запросов в адресной книге iOS
  • Ошибка ios-thread 1 exc_bad_instruction в приложении
  • Неполадка с помощью NSMutableArray sortUsingDescriptors: exception
  • Swift - Как создать запрос сортировки по убыванию на Firebase?
  • Запрос сортировки парсе через указатель
  • Interesting Posts
    Давайте будем гением компьютера.