0

我正在尝试根据与用户位置的接近程度使用地理点对淘汰赛可观察数组进行排序。我有一个函数可以遍历我的数组中的所有商店并找到离用户当前位置最近的标记。然后我将它嵌套在另一个循环中,使用插入排序对所有元素进行排序。

我有两个问题。第一的。我的交换方法有点时髦。我认为它打破了 dom。不要以为我理解如何在淘汰赛可观察到的情况下正确交换元素。

第二。这甚至是正确的方法吗?Ko 可观察数组有一个内置的排序方法,但我不确定如何使用最接近用户函数的点来实现它。我附上了下面的代码。任何帮助或见解将不胜感激。

var stores = ko.observableArray(); storesRepository.getFeed(stores);

function closestMarker(lat, lng){

            var pi = Math.PI;
            var R = 6371; //equatorial radius
            var lat1 = lat;
            var lon1 = lng;

            var distances, closest, min, chLat, chLon, dLat, dLon, rLat1, rLat2, a, c, d;

            for (j = 0; j < stores().length; j++) { // outer loop uses insertion sort to "sort" elements.
                 distances = [];
                 closest = -1;
                 min = 0;
                for (i = j+1; i < stores().length; i++) { // inner loop finds closest marker to user

                    var lat2 = stores()[i].latitude();
                    var lon2 = stores()[i].longitude();
                     chLat = lat2 - lat1;
                     chLon = lon2 - lon1;
                     dLat = chLat * (pi / 180);
                     dLon = chLon * (pi / 180);

                     rLat1 = lat1 * (pi / 180);
                    rLat2 = lat2 * (pi / 180);

                     a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
                            Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(rLat1) * Math.cos(rLat2);
                     c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
                     d = R * c;

                    distances[i] = d;
                    if (closest == -1 || d < distances[closest]) {
                        closest = i;
                    }


                }
                swap(j, closest);

            }
            function swap(a, b) { // i dont think this is the right approach
               // alert("working");
               var temp = stores()[b];
               stores.replace(stores()[b],stores()[a]);
               stores.replace(stores()[a], temp);

            }

        }
        return stores;
4

1 回答 1

0

几点:

在对可观察数组执行大量操作时,最好在底层数组上执行它们,然后在完成后向可观察数组发出信号。这将减少阵列的流失。

这是遵循上述规则的“更好”的交换实现:

function swap(a, b) {
    var ary = stores(),
        temp = ary[a];

    stores.valueWillMutate();
    ary[a] = ary[b];
    ary[b] = temp;
    stores.valueHasMutated();
}

既然我已经说过,您不应该使用它:) 您应该尝试使用内置sort函数而不是使用插入排序。这更好地遵循了第一条规则,仅在排序操作完成后才发送通知,而不是在每次交换时发送通知。并且内置排序使用本机浏览器代码,并且可能比您编写的 JavaScript 代码更快。您需要做的就是编写一个比较函数来指示 a 或 b 是否更接近用户,然后将其传递给 sort 方法:

var distanceToUser = function (a) {
    var lat2 = a.latitude(),
        lon2 = a.longitude(),
        chLat = lat2 - lat1,
        chLon = lon2 - lon1,
        dLat = chLat * pi / 180,
        dLon = chLon * pi / 180,
        rLat1 = lat1 * pi / 180,
        rLat2 = lat2 * pi / 180,
        aa = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
             Math.sin(dLon / 2) * Math.sin(dLon / 2) *
             Math.cos(rLat1) * Math.cos(rLat2),
        c = 2 * Math.atan2(Math.sqrt(aa), Math.sqrt(1 - aa));

    return R * c;
},
compare = function (a, b) {
    var da = distanceToUser(a),
        db = distanceToUser(b);

    return da < db ? -1 : (da > db ? 1 : 0);
};

stores.sort(compare);

如果您的数组中有大量项目stores,那么可以通过遍历数组一次来计算到用户的距离并将其存储为数组中每个项目的属性,然后将compare方法更改为只需比较这个距离属性。这将防止不断地一遍又一遍地重新计算距离。

于 2013-05-28T13:27:33.157 回答