【问题标题】:Sort array by distance from current location按与当前位置的距离对数组进行排序
【发布时间】:2015-09-21 19:06:46
【问题描述】:

我正在尝试按与当前位置的距离对数组进行排序。下面首先你会看到organizationObject,它包含不同的值,然后我们有位置,它是一个不同位置的数组。之所以是array,是因为一个组织可以有多个位置。然后在我的 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)]))

【问题讨论】:

    标签: ios arrays swift sorting


    【解决方案1】:

    这里有一个解决方案。由于几个原因,直接调用排序函数要复杂一些:首先需要为组织找到最近的位置,如问题中所述,其次是 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 的最近坐标似乎在哥本哈根郊区的某个城镇(另一个在里尔?),而 711 在瑞典。

    以下是如何使用该类(使用来自原始问题的测试数据,OrganizationObjects 中的 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)
    }
    

    【讨论】:

    • 你能举例说明如何使用这个类吗? :)
    • 哦,这是在操场上吗?
    • 刚刚用我使用的测试代码更新了答案——我没有使用游乐场,只是一个空项目。请注意,我更改了您的数据,因此组织的 ID 并非全为零
    • 谢谢 是的,数据中有一些错误,但这只是测试数据。谢谢
    • 嗯,我已经测试过了,它在两次打印中返回相同的顺序?是什么原因造成的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-19
    • 1970-01-01
    相关资源
    最近更新 更多