I have a multidimensional array of house properties:

$array = array(
    array('apn' => 345345353, 'sqft' => 1121, 'address' => '12 Lincoln Ave.'),
    array('apn' => 345345351, 'sqft' => 1643, 'address' => '13 Lincoln Ave.'),
    array('apn' => 345345352, 'sqft' => 1222, 'address' => '14 Lincoln Ave.')
    array('apn' => 345345358, 'sqft' => 1226, 'address' => '6 Olark Ave.')
    array('apn' => 345345345, 'sqft' => 1200, 'address' => '323 Pacific Ave.'),
    array('apn' => 345345342, 'sqft' => 1421, 'address' => '324 Pacific Ave.'),
    array('apn' => 345345347, 'sqft' => 1093, 'address' => '328 Pacific Ave.'),
);

What I want to create from it is an array with just the lowest and highest address for each street. If a street has only one address then it shouldn't show up in the array.

array('323 Pacific Ave.', '328 Pacific Ave.', '12 Lincoln Ave.', '14 Lincoln Ave.')

Currently I have the following function that works find but it is very verbose and I'm trying to figure out a simple way to sort by value in a multidimensional array.

function minMaxAddress($data) {
    $addressRanges = array();
    $streets = array();
    $numProperties = count($data);
    $i = 0;
    foreach ($data as $key => $listing) {
        $address = $listing['address'];
        $street = getStreetName($address);
        if ($i == 0) {
          $addressRanges[] = $address;
        }
        else if ($street != end($streets)) {
          $addressRanges[] = $lastAddress;
          $addressRanges[] = $address;
        }
        if ($i == $numProperties - 1) {
            $addressRanges[] = $address;
        }
        $streets[] = $street;
        $lastAddress = $address;
        $i++;
    }
    $addressRanges = array_diff($addressRanges, array_diff_assoc($addressRanges, array_unique($addressRanges)));
    $addressRanges = array_values($addressRanges);
    return $addressRanges;
}

migrated from stackoverflow.com May 23 '14 at 18:13

This question came from our site for professional and enthusiast programmers.

  • 1
    I can see the need to sort here, but considering that you have to group by street name first there's no need to sort any multidimensional array. Just break up the original into arrays of street numbers and process each one individually. – Jon May 21 '14 at 21:55

Assuming your input array is pre-grouped and pre-sorted as your posted code represents, then you can use a single loop with some conditionals like this:

Code: (Demo)

$result=[];  // declare empty array to keep array_push happy
$last=null;  // ensure first iteration doesn't match first address
foreach($array as $listing){
    $street=substr($listing['address'],strpos($listing['address'],' '));
    if($street!=$last){  // when there is a new street...
        if(isset($high)){   // check if the previous group contained a 'high'
            array_push($result,$low,$high);  // store low & high addresses
            unset($high);  // remove the high variable
        }
        $last=$street;  // temporarily preserve the street portion of the address
        $low=$listing['address'];  // temporarily preserve the low address
    }else{
        $high=$listing['address'];  // temporarily preserve the high address
    }
}
var_export($result);

Note, there are several methods to extract $street portion, substr()-strpos() is my preference for this snippet.


If your input array is not grouped and not sorted, then I use two loops to complete the task:

Code: (Demo)

foreach($array as $listing){
    list($number,$street)=explode(' ',$listing['address'],2);
    $buckets[$street][]=$number;  // create multi-dim array -- buckets of numbers
}
ksort($buckets);  // optionally sort on street name ASC
$result=[];  // declare empty array to keep array_push happy
foreach($buckets as $street=>$numbers){
    if(isset($numbers[1])){  // at least two values in bucket
        array_push($result,min($numbers)." $street",max($numbers)." $street");
    }
}
var_export($result);

Output for either method:

array (
  0 => '12 Lincoln Ave.',
  1 => '15 Lincoln Ave.',
  2 => '1 North St.',
  3 => '99 North St.',
  4 => '323 Pacific Ave.',
  5 => '328 Pacific Ave.',
)

p.s. I experimented with one other method based on your posted input array. In attempt to write a snippet with fewer lines, I leveraged array_column(), json_encode(), preg_match_all(), and array_walk() ...although it is technically shorter, I do not recommend it because handling array data as strings is not always reliable. This method does NOT work on a shuffled input array.

Code: (PHP Demo) (Regex Demo)

$json=json_encode(array_column($array,'address'));  // convert address values to single json string
$result=[];
if(preg_match_all('/"(\d+ ([^"]+))"(?:,"(\d+ \2,?)")+/',$json,$out)){  // capture 1st and last when possible
    array_walk($out[1],function($v1,$k,$v2)use(&$result){array_push($result,$v1,$v2[$k]);},$out[3]); // reunite
}
var_export($result);

...same result as the other methods -- for this input array anyhow.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.