3
\$\begingroup\$

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;
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ 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. \$\endgroup\$
    – Jon
    Commented May 21, 2014 at 21:55

1 Answer 1

2
\$\begingroup\$

While this task can be written as a single loop over your data, it would involve unnecessarily convoluted conditionals and temporary variables which will likely be an irritation to future developers (that person might actually be you) that may need to read your code.

I respect your desire to keep things terse, but great code isn't just brief, it is easily comprehensible. I feel that two loops will be the smartest approach. In the first loop, create a grouping array with the street name as keys and push each number into its respective street's subarray.

Then filter the group array for qualifying data (2 or more numbers in a group), extract the highest and lowest number, then append the bookend numbers to the street name.

Code: (Demo)

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

foreach ($array as $row) {
    [$number, $street] = explode(' ', $row['address'], 2);
    $group[$street][] = $number;
}

$result = [];
foreach ($group as $street => $numbers) {
    if (sizeof($numbers) > 1) {
        array_push($result, min($numbers) . ' ' . $street, max($numbers) . ' ' . $street);
    }
}

var_export($result);

Output:

array (
  0 => '12 Lincoln Ave.',
  1 => '14 Lincoln Ave.',
  2 => '323 Pacific Ave.',
  3 => '328 Pacific Ave.',
)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.