搜索或排序多维数组以获得最接近的lat和lon值

时间:2016-07-22 22:18:13

标签: php arrays sorting

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

例如,我将设置以下值:

Lat = 50.6000,Lon = -74.15000

我想搜索以下内容,并返回最接近匹配的数组。或者最接近最远的整个事情。

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

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

3 个答案:

答案 0 :(得分:1)

这里的函数就是这样....但是,它返回一个包含2个主要元素latitudeslongitudes的多维数组。经度包含最近经度值的所有已排序条目,“纬度”也包含最近纬度值的已排序条目。默认情况下,函数仅在纬度和纵向上返回非常接近的匹配。但是,在最后一个参数返回所有已排序的条目时传递false。下面的代码说明了一切:

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

答案 1 :(得分:0)

考虑:

$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

答案 2 :(得分:0)

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