2013-05-28 5 views
0

Я пытаюсь сортировать наблюдаемый массив нокаутом с использованием геотонов в соответствии с расстоянием до местоположения пользователей. У меня есть функция, которая перебирает все магазины в моем массиве и находит ближайший маркер для текущего местоположения пользователей. Затем im, вложенные в другой цикл, используя сортировку вставки для сортировки всех элементов.Нокаут наблюдаемого массива сортировать по географическому местоположению.

У меня есть две проблемы. Первый. Мой метод подкачки немного фанк. Я думаю, что он разбивает дом. Не думаю, что я понимаю, как правильно менять элементы в нокауте.

Второй. Это даже правильный подход? Ko наблюдаемый массив имеет встроенный метод сортировки, но не уверен, как его реализовать, используя ближайшую точку к пользовательской функции. Ive приложил код ниже. Любая помощь или понимание будут оценены.

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; 

ответ

0

Пару точек:

При выполнении серии манипуляций на наблюдаемом массиве, то лучше выполнять их на базовый массив, то сигнал наблюдаемый массив, когда вы закончите. Это уменьшит отброс массива.

Вот «лучше» осуществление обмена, который следует вышеуказанное правило:

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

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

Теперь, когда я сказал, что вы не должны использовать его :) Вы должны вместо этого попытаться использовать встроенные в функции sort вместо использования сортировки вставки. Это следует за первым правилом еще лучше, только отправив уведомление после завершения операции сортировки, а не на каждом свопе. И встроенная сортировка использует собственный код браузера и, скорее всего, будет быстрее, чем код JavaScript, который вы пишете. Все, что вам нужно сделать, это написать функцию сравнения, которая указывает, является ли или б ближе к пользователю, а затем передать его в метод сортировки:

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, чтобы просто сравнить это свойство расстояния. Это предотвратит постоянное повторное вычисление расстояния снова и снова.

+0

Отлично! Таким образом, вы передаете функцию в качестве аргумента методу сортировки и берете 2 параметра и определители того, как будет упорядочен массив. Все еще не совсем уверен, как работает базовая функция сортировки, но кажется, что она работает отлично! Благодаря! – sirFunkenstine

+0

Он использует встроенный 'Array.sort'. Этот API в основном такой же, как любой другой API сортировки массивов, который вы найдете на разных языках. Это было бы полезно прочитать специально для 'Array.sort': https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/sort – Brandon

Смежные вопросы