我正在尝试根据距当前位置的距离对数组进行排序。下面首先您会看到 organizationObject
,它包含不同的值,然后我们有位置,它是一个不同位置的数组。它之所以是一个数组
,是因为一个组织可以有多个位置。然后在我的 ViewController 中创建一组测试对象并附加到一个数组。我的问题是如何根据 distanceFromLocation 对 orgArray
进行排序?如果位置数组中有多个位置,它应该取最近的一个。
组织对象
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
}
}
将测试对象附加到数组。在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)]))
最佳答案
这是一个解决方案。由于几个原因,直接调用排序函数要复杂一些:首先,如问题中所述,需要为组织找到最近的位置,其次, 中使用了 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
}
}
我已经在您的示例数据上对其进行了测试,使用哥本哈根克里斯蒂安堡宫的位置作为测试地点,并获得了以下排序:
Kongens have
Statens Museum For Kunst
Magasin du nord
7 eleven
这似乎与给定的坐标相匹配 - 看起来最近的 Magasin du Nord 坐标在哥本哈根郊区的某个小镇(另一个在里尔?),而 7 点 11 分在瑞典。
这是类的使用方式(使用原始问题中的测试数据,OrganizationObject
中的 id
值已更改,因此它们不全为 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)
}
关于ios - 按与当前位置的距离对数组进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32702785/