Mike Q Mike Q - 4 months ago 17
PHP Question

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

This may be difficult, I want to search the following multi-dimensional array based on closest match of lat and lon and return that sub-array.

For example I will have the following values already set:

Lat=50.6000, Lon=-74.15000

And I want to search the following, and return the array that is the closest match. Or sort the whole thing by closest to furthest.

Even better would be a way to just sort the list so the closest lat/lon are first down to the furthest away from. What I DON'T need is it sorted in descending order. I needs to be closest to the preset value above for example. Anyone have an idea?

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

Answer

The Function here would do just that.... however, it returns a Multidimensional Array with with 2 major Elements latitudes and longitudes. The longitudes hold all the sorted Entries for the closest longitude values and the "latitudes" as well hold the sorted Entries for the closest latitude values. By default, the Function only returns the very Closest Match latitudinally and longitudinally. However, passing false as the last Parameter returns all sorted entries. The Code below illustrates it all:

<?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;
    }
The lines: $nearestLongLat = sortByNearestLatLong($arrGeoData, 50.6000, -74.15000); var_dump(nearestLongLat); above produces something like below. Notice the latitudes and longitudes keys
    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)
Now, we try again with a different set of Coordinates: $nearestLongLat = sortByNearestLatLong($arrGeoData, 25.6000, -84.15000); var_dump($nearestLongLat);. This produces:
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)
Comments