2016-07-22 3 views
0

Dies kann schwierig sein. Ich möchte das folgende mehrdimensionale Array basierend auf der engsten Übereinstimmung von lat und lon durchsuchen und dieses Sub-Array zurückgeben.Suchen oder Sortieren multidimensionales Array für die nächsten Lat- und Lon-Werte

Zum Beispiel werde ich die folgenden Werte haben bereits festgelegt:

Lat = 50,6000, Lon = -74,15000

Und ich möchte folgendes, und schicken Sie das Array suchen, die die beste Übereinstimmung ist. Oder sortiere das Ganze am nächsten.

Noch besser wäre eine Möglichkeit, die Liste so zu sortieren, dass die nächstgelegenen lat/lon am weitesten entfernt sind. Was ich NICHT brauche, ist in absteigender Reihenfolge sortiert. Ich muss zum Beispiel dem voreingestellten Wert am nächsten sein. Jeder hat eine Idee?

Array 
(
[0] => Array 
    (
     [zipcode] => 28299 
     [latitude] => 36.234982 
     [longitude] => -81.913799 
     [cityname] => ACME 
    ) 

[1] => Array 
    (
     [zipcode] => 17198 
     [latitude] => 50.735880 
     [longitude] => -74.143855 
     [cityname] => NEWLAND 
    ) 

[2] => Array 
    (
     [zipcode] => 12203 
     [latitude] => 41.711931 
     [longitude] => -75.011806 
     [cityname] => ACE 
    ) 
) 
+0

Also im obigen Beispiel würde Array [1] zurückgeben. Oder wenn es alles zurückgeben könnte, würde es in der Reihenfolge basierend auf der Entfernung zurückkehren: Array [1], Array [2], Array [0] in dieser Reihenfolge. Hoffentlich mache ich Sinn. –

+0

eigentlich, was ich tun muss, ist addieren Sie den ABS-Wert von lat und lang und die kleinste wäre die nächste zu meinen .. Ich denke? –

Antwort

2

Die Funktion hier würde genau das tun .... aber es gibt ein multidimensionales Array mit mit 2 großen Elementen latitudes und longitudes. Die Längen enthalten alle sortierten Einträge für die engsten Längengrad Werte und die "Breitengrade" sowie halten die sortierten Einträge für die nächsten Breitengrad Werte. Standardmäßig gibt die Funktion nur die kleinste Übereinstimmung in Breiten- und Längsrichtung zurück. Die Übergabe von false als letzten Parameter gibt jedoch alle sortierten Einträge zurück. Der folgende Code zeigt alles:

<?php 
    $arrGeoData = array(
     array(
      "zipcode" => 28299, 
      "latitude" => 36.234982, 
      "longitude" => -81.913799, 
      "cityname" => "ACME", 
     ), 
     array(
      "zipcode" => 17198, 
      "latitude" => 50.735880, 
      "longitude" => -74.143855, 
      "cityname" => "NEWLAND", 
     ), 
     array(
      "zipcode" => 12203, 
      "latitude" => 41.711931, 
      "longitude" => -75.011806, 
      "cityname" => "ACE", 
     ), 
    ); 
    $nearestLongLat  = sortByNearestLatLong($arrGeoData, 50.6000, -74.15000); 
    var_dump(nearestLongLat); 

    function sortByNearestLatLong($geoData, $lat, $long, $returnNearestOnly=true){ 
     // CREATE AN ARRAY FOR USE INSIDE THE FUNCTION 
     $arrCloseMatchLat = array(); 
     $arrCloseMatchLong = array(); 
     $matchedGeoSet  = array(); 

     // LOOP THROUGH ALL THE $geoData ARRAY AND SUBTRACT THE GIVEN LAT & LONG VALUES 
     // FROM THOSE CONTAINED IN THE ORIGINAL ARRAY: $geoData 
     // WE KNOW THAT THE SMALLER THE RESULT OF THE SUBTRACTION; THE CLOSER WE ARE 
     // WE DO THIS FOR BOTH THE LONGITUDE & LATITUDE... HENCE OUR ARRAY: 
     // $arrCloseMatchLat AND $arrCloseMatchLong RESPECTIVELY 
     foreach($geoData as $iKey=>$arrGeoStrip){ 
      $arrCloseMatchLat[$iKey] = abs(floatval(($arrGeoStrip['latitude']) - $lat )); 
      $arrCloseMatchLong[$iKey] = abs(floatval(($arrGeoStrip['longitude']) - $long)); 
     } 


    // WE SORT BOTH ARRAYS NUMERICALLY KEEPING THE KEYS WHICH WE NEED FOR OUR FINAL RESULT 
     asort($arrCloseMatchLat, SORT_NUMERIC); 
     asort($arrCloseMatchLong, SORT_NUMERIC); 

     // WE CAN RETURN ONLY THE RESULT OF THE FIRST, CLOSEST MATCH 
     if($returnNearestOnly){ 
      foreach($arrCloseMatchLat as $index=>$difference){ 
       $matchedGeoSet['latitudes'][] = $geoData[$index]; 
       break; 
      } 
      foreach($arrCloseMatchLong as $index=>$difference){ 
       $matchedGeoSet['longitudes'][] = $geoData[$index]; 
       break; 
      } 
      // OR WE CAN RETURN THE ENTIRE $geoData ARRAY ONLY SORTED IN A "CLOSEST FIRST" FASHION... 
      // WE DO THIS FOR BOTH THE LONGITUDE & LATITUDE RESPECTIVELY SO WE END UP HAVING 2 
      // ARRAYS: ONE THAT SORTS THE CLOSEST IN TERMS OF LONG VALUES 
      // AN ONE THAT SORTS THE CLOSEST IN TERMS OF LAT VALUES... 
     }else{ 
      foreach($arrCloseMatchLat as $index=>$difference){ 
       $matchedGeoSet['latitudes'][] = $geoData[$index]; 
      } 
      foreach($arrCloseMatchLong as $index=>$difference){ 
       $matchedGeoSet['longitudes'][] = $geoData[$index]; 
      } 
     } 
     return $matchedGeoSet; 
    } 
Die Linien: $ nearestLongLat = sortByNearestLatLong ($ arrGeoData, 50,6000, -74,15000); var_dump (nearestLongLat); oben produziert etwas wie unten. Beachten Sie die Breiten- und Längenschlüssel
array (size=2) 
     'latitudes' => 
     array (size=1) 
      0 => 
      array (size=4) 
       'zipcode' => int 17198 
       'latitude' => float 50.73588 
       'longitude' => float -74.143855 
       'cityname' => string 'NEWLAND' (length=7) 
     'longitudes' => 
     array (size=1) 
      0 => 
      array (size=4) 
       'zipcode' => int 17198 
       'latitude' => float 50.73588 
       'longitude' => float -74.143855 
       'cityname' => string 'NEWLAND' (length=7) 
Nun wir versuchen Sie es mit einem anderen Satz von Koordinaten: $ nearestLongLat = sortByNearestLatLong ($ arrGeoData, 25,6000, -84,15000); var_dump ($ nearestLongLat);. Dies erzeugt:
array (size=2) 
    'latitudes' => 
    array (size=1) 
     0 => 
     array (size=4) 
      'zipcode' => int 28299 
      'latitude' => float 36.234982 
      'longitude' => float -81.913799 
      'cityname' => string 'ACME' (length=4) 
    'longitudes' => 
    array (size=1) 
     0 => 
     array (size=4) 
      'zipcode' => int 28299 
      'latitude' => float 36.234982 
      'longitude' => float -81.913799 
      'cityname' => string 'ACME' (length=4) 
+0

Shoot, eigentlich funktioniert das nicht ... Versuchen Sie es mit anderen Werten und es erzeugt das gleiche Ergebnis –

+0

@MikeQ Welche anderen Werte haben Sie versucht? – Poiz

+0

@MikeQ Der Code ist aktualisiert .... das Problem war 'arsort ($ arrCloseMatchLat, SORT_NUMERIC);' anstelle von 'asort ($ arrCloseMatchLat, SORT_NUMERIC);'.Versuchen Sie es noch einmal – Poiz

0

Bedenken Sie:

$cities = <your array>; 

$point = array(
    'latitude' => 50.6000, 
    'longitude' => -74.15000 
); 

function distance($a, $b) { 
    return sqrt(
     pow($a['latitude'] - $b['latitude'], 2) 
     + pow($a['longitude'] - $b['longitude'], 2)); 
} 

usort($cities, function($p, $q) { 
    global $point; 
    return distance($p, $point) - distance($q, $point); 
}); 

Dies verwendet die naive Formel euklidischen Abstandes, für genauere Berechnungen ersetzen distance mit einem der hier aufgeführten Formeln: https://en.wikipedia.org/wiki/Geographical_distance

+0

Danke für die Antwort, ich denke, dass sollte diese Formel nicht verwenden müssen, wenn ich nur Zahlen vergleiche, ist das falsch anzunehmen? –

+0

@MikeQ: Wenn Sie nach Punkten suchen, die nahe beieinander liegen, vergleichen Sie ihre Entfernungen, nicht die Koordinaten. Siehe auch unten. – georg

0

Ich glaube, ich kann kombiniere die Berechnung und gebe das ganze Array in der Reihenfolge ein bisschen besser zurück, wenn ich es so mache. Müssen einige Tests machen, aber es sieht soweit korrekt aus. @ poiz

function sort2ByNearestLatLong($geoData, $lat, $long, $returnNearestOnly=false){ 

    $arrCloseMatch = array(); 
    $matchedGeoSet = array(); 

    // LOOP THROUGH ALL THE $geoData ARRAY AND SUBTRACT THE GIVEN LAT & LONG VALUES 
    // FROM THOSE CONTAINED IN THE ORIGINAL ARRAY: $geoData 
    // WE KNOW THAT THE SMALLER THE RESULT OF THE SUBTRACTION; THE CLOSER WE ARE 
    // WE DO THIS FOR BOTH THE LONGITUDE & LATITUDE... HENCE OUR ARRAY 
    // $arrClostMatch and add the values calculated for Lat/Lon: 
    foreach($geoData as $iKey=>$arrGeoStrip){ 
     $arrCloseMatch[$iKey] = abs(floatval(($arrGeoStrip['latitude']) - $lat)) + abs(floatval(($arrGeoStrip['longitude']) - $long)); 
    } 

    // SORT ARRAY NUMERICALLY KEEPING THE KEYS WHICH WE NEED FOR OUR FINAL RESULT 
    asort($arrCloseMatch, SORT_NUMERIC); 

    // RETURN CLOSEST OR FULL LIST 
    foreach($arrCloseMatch as $index=>$difference){ 

      $matchedGeoSet['latitudes'][] = $geoData[$index]; 
      if ($returnNearestOnly==true) { 
        break; 
      } 
    } 

    return $matchedGeoSet; 
} 
+0

@Poiz dies ist eine Überarbeitung von dem, was Sie gepostet .. Gedanken? –

+1

Diese Formel sieht nicht korrekt aus, z. es besagt, dass die Abstände zwischen "(0,0)" und "(0,4)" und zwischen "(0,0)" und "(2,2)" gleich sind, was nicht der Fall ist. – georg

+0

@georg GROSSE FRAGE. Ich stimme jedoch zu, dachte Experiment - Meine Ergebnisse geben 5 chicago Städte dann etwas weiter weg, so dass diese 5 Städte werden immer sehr ähnlich in Zahlen, so dass es immer funktioniert. Die anderen Ergebnisse werden viel weiter entfernt sein und daher fehlschlagen. Es scheint also zu funktionieren ... Ich werde noch mehr testen und es euch wissen lassen :-) –

Verwandte Themen