ios - 按与当前位置的距离对数组进行排序

标签 ios arrays swift sorting

我正在尝试根据距当前位置的距离对数组进行排序。下面首先您会看到 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 计算CLLocationdistanceFromLocation: 方法如果使用不当会减慢速度。

出于这些原因,我创建了一个特殊对象来进行排序,这样我就可以使用成员字典来 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/

相关文章:

java - 为什么我不能让用户提示变量是数组大小?

ios - UIView 中的 CAShapeLayer 抠图

swift - 结合 CoreML 和 ARKit

ios - 动态更新约束不起作用

java - .length 函数始终返回 0

r - 为什么给出0时没有+号?

ios - Google Analytics 实时功能不起作用

iphone - SDWebImage 未运行

ios - AV播放器 : difference between observedBitrate and indicatedBitrate

objective-c - IOS 上的波形