2
\$\begingroup\$

There is a clear pattern as to what the number values would be. And this has a starting interval and known start and end value. Though the end may change, it seems simpler to set the values and do some magical loop. Any better formats would be appreciated. The sets are what I would have gone with if I could have gotten the loop to work correctly.

<?php
$setStart =5000;
$setEnd = 95000;
$setInterval = 5000;

    //Enter your code here, enjoy!

    foreach($zips as $zipcode) {
    $zip = $zipcode['zip'];
    $zipInt = intval($zipcode['zip']);
    $org_ids = $zipcode['orgs'];
    $org_ids = explode(",",$org_ids);
    if (!empty($org_ids)) {
        if ($zipInt < 5000) {
            $zips00_array[$zip] = $org_ids;
        }
        if ($zipInt >= 5000 && $zipInt < 10000) {
            $zips05_array[$zip] = $org_ids;
        }
        if ($zipInt >= 10000 && $zipInt < 15000) {
            $zips10_array[$zip] = $org_ids;
        }
        if ($zipInt >= 15000 && $zipInt < 20000) {
            $zips15_array[$zip] = $org_ids;
        }
        if ($zipInt >= 20000 && $zipInt < 25000) {
            $zips20_array[$zip] = $org_ids;
        }
        if ($zipInt >= 25000 && $zipInt< 30000) {
            $zips25_array[$zip] = $org_ids;
        }
        if ($zipInt >= 30000 && $zipInt < 35000) {
            $zips30_array[$zip] = $org_ids;
        }
        if ($zipInt >= 35000 && $zipInt < 40000) {
            $zips35_array[$zip] = $org_ids;
        }
        if ($zipInt >= 40000 && $zipInt < 45000) {
            $zips40_array[$zip] = $org_ids;
        }
        if ($zipInt >= 45000 && $zipInt < 50000) {
            $zips45_array[$zip] = $org_ids;
        }
        if ($zipInt >= 50000 && $zipInt < 55000) {
            $zips50_array[$zip] = $org_ids;
        }
        if ($zipInt >= 55000 && $zipInt < 60000) {
            $zips55_array[$zip] = $org_ids;
        }
        if ($zipInt >= 60000 && $zipInt < 65000) {
            $zips60_array[$zip] = $org_ids;
        }
        if ($zipInt >= 65000 && $zipInt < 70000) {
            $zips65_array[$zip] = $org_ids;
        }
        if ($zipInt >= 70000 && $zipInt < 75000) {
            $zips70_array[$zip] = $org_ids;
        }
        if ($zipInt >= 75000 && $zipInt < 80000) {
            $zips75_array[$zip] = $org_ids;
        }
        if ($zipInt >= 80000 && $zipInt < 85000) {
            $zips80_array[$zip] = $org_ids;
        }
        if ($zipInt >= 85000 && $zipInt < 90000) {
            $zips85_array[$zip] = $org_ids;
        }
        if ($zipInt >= 90000 && $zipInt < 95000) {
            $zips90_array[$zip] = $org_ids;
        }
        if ($zipInt >= 95000) {
            $zips95_array[$zip] = $org_ids;
        }
    }
}
\$\endgroup\$
  • \$\begingroup\$ Aren't you meant to provide sample data for zips so that the code is runnable? (I'm new here) \$\endgroup\$ – mickmackusa Sep 17 '17 at 11:18
1
\$\begingroup\$

As Trevor mentions, variable variables can be employed to eliminate all those if statements.

One way to achieve this is to take the first two digits of the zip code and divide them by 5, use floor() to round down and then multiply by 5 to get the bucket number.

 $firstTwo = substr($zip, 0, 2);
 $bucket = floor($firstTwo / 5) * 5;
 if ($bucket < 10) { //ensure we have two digits
     $bucket = '0'.$bucket;
 }
 $variable = 'zips'.$bucket.'_array';
 $$variable[$zip] = $org_ids;

See a demonstration of this in this playground example.

Another approach would be to have a 2-diminsional array of ranges and group the zip codes based on the range that each fits into. Something like:

$zips = array();
foreach($zips as $zipcode) {
    $zip = $zipcode['zip'];
    $org_ids = $zipcode['orgs'];
    $bucket = floor(substr($zip, 0, 2) / 5) * 5;
    $bucket = ($bucket < 10)?'0'.$bucket:$bucket;
    $zips[$bucket][$zip] = $org_ids;
}
\$\endgroup\$
  • \$\begingroup\$ I like both the approaches. Both address the $zips##_array[$zip]. But neither address the if statements like these. They are always 5,000 apart. with a known starting point and a known ending point. if ($zipInt >= 35000 && $zipInt < 40000) { $zips35_array[$zip] = $org_ids; } \$\endgroup\$ – OJ Johnson Sep 18 '17 at 14:43
  • \$\begingroup\$ Am I missing something? that scenario you gave should still be handled - e.g. $zipInt == 38024: will go into $zips35_array[$zip]... proof... \$\endgroup\$ – Sᴀᴍ Onᴇᴌᴀ Sep 18 '17 at 15:39
2
\$\begingroup\$

I think you could use a one-liner like:

$zip_arr_id = floor(($zipInt/1000)/5 )*5;

which could correspond to the $zips${$zip_arr_id}_array (unsure if this is exactly right) that you're saving the org ID's to. Look into variable variables in php.

Riffing on this idea could save you a lot of lines in your code.

\$\endgroup\$
2
\$\begingroup\$

You are storing a multi-dimensional volume of data in a collection of 20 one-dimensional arrays. While this approach may be successful, it will not enjoy the ease and simplicity of data access and iteration like a multi-dimensional array would.

In the great majority of situations, using variable variables is evidence of poor programming design (there may be fringe cases where it is acceptable, but unless you can provide a compelling reason, avoid using variable variables).

Pure arithmetic and the floor() function will succinctly generate bucket keys for you. Then you can preserve the zipcodes as keys for deeper indexed arrays holding the individual/exploded org_ids.

I've eliminated any single-use variables as a matter of best practice and slightly altered some of the variable names in an attempt to improve comprehension.

If you need 00 & 05 (bucket keys as zero-padded strings), str_pad() can be used during declarations -- but I doubt this is an issue based on your provided working code.

Code: (Demo)

$zip_orgs=[
    ['zip'=>'03217','orgs'=>'1,3,29'], // Ashland, NH
    ['zip'=>'15219','orgs'=>'6,10,17,33'], // Pittsburg, PA
    ['zip'=>'41702','orgs'=>'4'], // Hazard, KY
    ['zip'=>'17001','orgs'=>'7,18'], // Camp Hill, PA
    ['zip'=>'63101','orgs'=>'2,9'], // St. Louis, MO
    ['zip'=>'90213','orgs'=>'5'] // Beverly Hills, CA
];

// sort($zip_orgs) // if desired/necessary sort by 'zip' ASC, 'orgs' ASC

/* if you wish to generate buckets with empty subarrays by default...
    // bucket ids reduced by 1000
    $min=0;
    $max=95;
    $step=5;
    $buckets=array_fill_keys(range($min,$max,$step),[]);
*/

foreach($zip_orgs as $entry){
    $buckets[floor($entry['zip']/5000)*5][$entry['zip']]=explode(',',$entry['orgs']);
}

var_export($buckets);

Output:

array (
  0 => 
  array (
    '03217' => 
    array (
      0 => '1',
      1 => '3',
      2 => '29',
    ),
  ),
  15 => 
  array (
    15219 => 
    array (
      0 => '6',
      1 => '10',
      2 => '17',
      3 => '33',
    ),
    17001 => 
    array (
      0 => '7',
      1 => '18',
    ),
  ),
  40 => 
  array (
    41702 => 
    array (
      0 => '4',
    ),
  ),
  60 => 
  array (
    63101 => 
    array (
      0 => '2',
      1 => '9',
    ),
  ),
  90 => 
  array (
    90213 => 
    array (
      0 => '5',
    ),
  ),
)

Just an extra note about your posted code block: You didn't need to compare using >= because there are no US zipcodes that end in 000; so > would have sufficed.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.