5
\$\begingroup\$

I wanted to make a dynamic select statement from this year to 10 years. This gets the job done, but I feel like it's a little much.

 form_dropdown('year', array_combine(range(date('Y'), date('Y')+10), range(date('Y'), date('Y')+10)), set_value('year'));

Specifically, is there a better way to create this array, other than this?

array_combine(range(date('Y'), date('Y')+10), range(date('Y'), date('Y')+10))

Desired output (at least for this year):

Array
(
    [2014] => 2014
    [2015] => 2015
    [2016] => 2016
    [2017] => 2017
    [2018] => 2018
    [2019] => 2019
    [2020] => 2020
    [2021] => 2021
    [2022] => 2022
    [2023] => 2023
    [2024] => 2024
)
\$\endgroup\$
4
\$\begingroup\$

In order to get the output that you wanted, using array_combine will most likely be your best bet. You can simplify your statements pretty easily because variables are you friends:

$current_year = date('Y');
$date_range = range($current_year, $current_year+10);

form_dropdown('year', array_combine($date_range, $date_range), set_value('year'));

Addendum by @brettsantore

I think this solves what I thought to be a problem, the combining of so many functions. I ended up simplifying it a little more.

$current_year = date('Y');
$range = range($current_year, $current_year+10);
$years = array_combine($range, $range);
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I apologize for adding to your answer, but found writing that as a comment would have been absurd. \$\endgroup\$ – Brett Santore Jul 1 '14 at 17:04
1
\$\begingroup\$

(I'm leaving the original answer intact for posterity, but please read the edit at the bottom of the answer as the answer is wrong).

Why create a complicated line of code, such as:

array_combine(range(date('Y'), date('Y')+10), range(date('Y'), date('Y')+10))

When you can do a simple for-loop, such as:

$current_year = date('Y');
$max_year = $current_year + 10;
for($i = $current_year; $i <= $max_year; $i++){
    $year_array[$i] = $i;
}

Well - speed. The one liner mixture of array_combine(), range() and date() is multiple times faster than the for-loop. Not to mention that it creates less work for the GC.

I ran the two pieces of code above and this was the output:

$start_0 = microtime();
$year_array = array_combine(range(date('Y'), date('Y')+10), range(date('Y'), date('Y')+10));
$end_0 = microtime();

$start_1 = microtime(true);
$current_year = date('Y');
$max_year = $current_year + 10;
$year_array = array();
for($i = $current_year; $i <= $max_year; $i++){
    $year_array[$i] = $i;
}
$end_1 = microtime(true);

echo "<pre>";
print_r($year_array);
echo "0 Time: " . ($end_0 - $start_0) . "<br>";
echo "1 Time: " . ($end_1 - $start_1) . "<br>";
echo "</pre>";

Benchmark of the two pieces of code

Now, even if we make use of inlining the function calls, it gets even worse! See:

$start_0 = microtime();
$year_array = array_combine(range(date('Y'), date('Y')+10), range(date('Y'), date('Y')+10));
$end_0 = microtime();

$start_1 = microtime(true);
$year_array = array();
for($i = date('Y'); $i <= date('Y') + 10; $i++){
    $year_array[$i] = $i;
}
$end_1 = microtime(true);

echo "<pre>";
print_r($year_array);
echo "0 Time: " . ($end_0 - $start_0) . "<br>";
echo "1 Time: " . ($end_1 - $start_1) . "<br>";
echo "</pre>";

Benchmark of the two pieces of code, inlining date()

So, the best option is to go the array_combine(), range(), date() route. However, we can further optimize it as:

$start_range = date('Y');
$range = range($start_range, $start_range + 10)
array_combine($range, $range)

That way, we end up with 2 function calls to date(), range() and 2 new variables (which are cheaper than a function call), but is still not as performant as your original one liner.

$start_0 = microtime();
$year_array = array_combine(range(date('Y'), date('Y')+10), range(date('Y'),, date('Y')+10));
$end_0 = microtime();

$start_1 = microtime(true);
$year_array = array();
for($i = date('Y'); $i <= date('Y') + 10; $i++){
    $year_array[$i] = $i;
}
$end_1 = microtime(true);

$start_2 = microtime(true);
$start_range = date('Y');
$range = range($start_range, $start_range + 10);
array_combine($range, $range);
$end_2 = microtime(true);

echo "<pre>";
print_r($year_array);
echo "0 Time: " . ($end_0 - $start_0) . "<br>";
echo "1 Time: " . ($end_1 - $start_1) . "<br>";
echo "2 Time: " . ($end_2 - $start_2) . "<br>";
echo "</pre>";

Benchmark of the three pieces of code

My recommendation would be to keep your one liner.

EDIT: My recommendation is you do #2 as I missed microtime(true) on $start_0 and $end_0, thus I completely misread the benchmark output (which would make the one liner the slowest of the three tests). Thank you for catching that @Brett Santore.

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ It appears you ran test 0 without microtime(true), with 1.09E-5 or (0.0000109) < .0001. Wouldn't that support test 2 being faster with only 3 function calls? \$\endgroup\$ – Brett Santore Jul 1 '14 at 17:20
  • 1
    \$\begingroup\$ Ah drats. Yeah, you're right. Tests 1 and 2 are increasingly faster by a near 10x magnitude: i.imgur.com/JZEi3PY.png \$\endgroup\$ – jsanc623 Jul 1 '14 at 17:40
  • 1
    \$\begingroup\$ Fantastic contribution \$\endgroup\$ – Brett Santore Jul 1 '14 at 17:42
  • 1
    \$\begingroup\$ I added an edit at the top and bottom clarifying the incorrectness of the answer. I also left the original answer intact for posterity. \$\endgroup\$ – jsanc623 Jul 1 '14 at 17:43

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.