在多维数组中搜索或排序最接近的lat和lon值


Search or sort multi dimensional array for closest lat and lon values

这可能很困难,我想根据lat和lon的最接近匹配搜索以下多维数组,并返回该子数组。

例如,我已经设置了以下值:

Lat=50.6000,Lon=-741.5000

我想搜索以下内容,并返回最匹配的数组。或者按最接近到最远的方式对整件事进行排序。

更好的方法是对列表进行排序,使最接近的纬度/经度先向下到最远离的纬度/纬度。我不需要的是按降序排列。例如,我需要最接近上面的预设值。有人有主意吗?

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
    )
)

这里的函数就是这样做的。。。。然而,它返回具有两个主要元素latitudeslongitudes的多维数组。经度包含最近经度值的所有排序条目,"纬度"也包含最近纬度的排序条目。默认情况下,函数仅在纵向和纵向上返回最接近的匹配。但是,将false作为最后一个Parameter传递会返回所有排序的条目。下面的代码说明了这一切:

<?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;
    }
行数:$nearestLongLat=sortByNearestLatLong($arrGeoData,50.6000,-74.15000);var_dump(nearestLongLat)上面产生类似下面的东西。请注意纬度和经度键
    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)
现在,我们使用不同的坐标集重试:$nearestLongLat=sortByNearestLatLong($arrGeoData,25.6000,-84.15000);var_dump($nearestLongLat)。这将生成:
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)

考虑:

$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);
});

这使用了天真的欧几里得距离公式,为了更准确的计算,将distance替换为此处列出的公式之一:https://en.wikipedia.org/wiki/Geographical_distance

我想如果我这样做的话,我可以组合计算并按顺序返回完整的数组。需要做一些测试,但到目前为止看起来是正确的@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;
}