2013-05-28 56 views
0

我正在嘗試使用根據用戶位置的接近度的地理位置對可視化陣列進行排序。我有一個函數循環遍歷數組中的所有商店,並找到最接近用戶當前位置的標記。然後即時嵌套在另一個循環內,使用插入排序對所有元素進行排序。按地理位置排序可觀察數組排序。

我有兩個問題。第一。我的交換方法有點時髦,我認爲它打破了死亡。不要以爲我明白如何在淘汰賽中正確交換elemts。

二。這甚至是正確的方法嗎? 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; 

回答

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是否更貼近用戶,然後將它傳遞給排序方法:

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

太棒了!所以你將一個函數作爲參數傳遞給sort方法,並且需要2個參數和確定器如何排序數組。仍然不完全確定底層排序函數是如何工作的,但它似乎完美地工作!謝謝! – sirFunkenstine

+0

它使用內置的'Array.sort'。這個API基本上與您在各種語言中找到的任何其他數組排序API相同。這對於Array.sort特別有用:https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/sort – Brandon