在距离上对很多位置进行排序的最快方法是什么?

时间:2010-10-14 14:45:55

标签: iphone objective-c core-data core-location

我想在距离当前位置的距离上排序很多位置(航点)。 当然,当前位置是移动目标,因此对于每个位置更新,重新计算每个位置的距离是必要的。但只有重新计算附近的位置就足够了。

我目前使用核心数据,并在configurecell:atindexpath:方法中将距离存储为当前位置作为表中的属性(但仅在更改时更新)。 这类工作,但应用程序没有响应,而核心数据自动更新所有距离。这适用于250个位置,但是5000个崩溃。 我需要它才能在10.000个位置工作,尽管我可能只需要距离最近的1000个位置。

我还没试过的想法: 将所有距离存储在单独的内存数组中,只记录记录ID和距离。然后按距离对数组进行排序。问题是我不能使用FetchedResultsController,因为数据库中没有排序字段。

使用谓词根据纬度和经度过滤位置。然后只显示过滤后的位置。

在单独的线程中重新计算距离。

这些想法似乎都不容易尝试。

有人提出建议,不同的想法,对我的想法有所不同吗?

3 个答案:

答案 0 :(得分:1)

听起来你需要将你的位置转换为希尔伯特曲线上的位置 - 然后点“靠近”你是一个简单的减法?

Mapping N-dimensional value to a point on Hilbert curve

不能说我知道里面的技术,但那是我开始看的地方

答案 1 :(得分:1)

如果重要的是顺序(而不是准确的距离),您可以在移动窗口中对航点序列的切片进行排序(即,将项目 i 排序到 i + n ,其中 i 更改)。从航点序列的开头开始。排序 n 项目(n = 10是一个很好的起点)。如果任何项目改变位置,则向前移动窗口 n / 2 (尝试使用不同的偏移或算法来选择偏移)并重复。根据航点在当前位置附近的密集程度,我预计这只会在几种情况下停止。

请注意,我没有想过这么长时间来说明这是否真的有效。

在你提到的三个选项中,我最喜欢使用线程。这是处理无响应用户界面的经典方式,当它被大量计算阻止时。

答案 2 :(得分:0)

我将我的位置作为纬度/经度坐标存储在数据模型中。然后我写了一些辅助扩展来找到lat / lon坐标的半矩形区域并通过它进行查询。这是我正在使用的代码。我知道这个问题是针对Objective-C的,但问题是陈旧的,现在大多数人都在寻找Swift的答案。

Swift 3

   extension CLLocationDistance {
        var feet: Double {
            return self * 3.28084
        }
        var miles: Double {
            return self.feet / 5280.0
        }
    }

    extension CLLocationDegrees {
        static var north: CLLocationDegrees {
            return 90.0
        }
        static var south: CLLocationDegrees {
            return -90.0
        }
        static var east: CLLocationDegrees {
            return 180.0
        }
        static var west: CLLocationDegrees {
            return -180.0
        }

        var radians: Double {
            return Double.pi * self / 180.0
        }
    }

    extension CLLocationCoordinate2D {
        static var origin: CLLocationCoordinate2D {
            return CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
        }

        static var northPole: CLLocationCoordinate2D {
            return CLLocationCoordinate2D(latitude: 90.0, longitude: 0.0)
        }

        static var southPole: CLLocationCoordinate2D {
            return CLLocationCoordinate2D(latitude: 90.0, longitude: 0.0)
        }

        var metersPerDegreeLatitude: CLLocationDistance {
            return 111319.4907932736
        }
        var metersPerDegreeLongitude: CLLocationDistance {
            return max(0.0, cos(self.latitude.radians) * self.metersPerDegreeLatitude)
        }
    }

    extension CLCircularRegion {
        var northernmostLatitude: CLLocationDegrees {
            let longitude = self.center.latitude + self.radius / self.center.metersPerDegreeLatitude
            return min(longitude, .north)
        }

        var southernmostLatitude: CLLocationDegrees {
            let longitude = self.center.latitude - self.radius / self.center.metersPerDegreeLatitude
            return max(longitude, .south)
        }

        var easternmostLongitude: CLLocationDegrees {
            guard self.northernmostLatitude <= .north else {
                return .east
            }
            guard self.southernmostLatitude >= .south else {
                return .east
            }
            return min(.east, self.center.longitude + self.radius / (self.center.metersPerDegreeLongitude + 0.0001))
        }

        var westernmostLongitude: CLLocationDegrees {
            guard self.northernmostLatitude <= .north else {
                return .west
            }
            guard self.southernmostLatitude >= .south else {
                return .west
            }
            return max(.west, self.center.longitude - self.radius / (self.center.metersPerDegreeLongitude + 0.0001))
        }

        func buildPredicate(latitudeName: String = "latitude", longitudeName: String = "longitude") -> NSPredicate {
            let args = [self.southernmostLatitude, self.northernmostLatitude, self.westernmostLongitude, self.easternmostLongitude]
            return NSPredicate(format: "\(latitudeName) >= %@ && \(latitudeName) <= %@ && \(longitudeName) >= %@ && \(longitudeName) <= %@", argumentArray: args)
        }
    }