Page 1 of 1

Smart way to sort my 1 dim array

Posted: Mon Feb 01, 2010 3:49 am
by papa
'elo,

I have a simple array:

Code: Select all

$months = array(1=>"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");
If I want to show March to January is the a clever way of sorting this or do I need to create a new array?

Edit:

This is what I've done.

Code: Select all

 
$cur_month = date('n');
 
$months = array(1=>"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");
 
function setMonth($cur_month) { ... }
 
$m =  setMonth($cur_month);
 
$n = array();
 
foreach($months as $key => $month)
{
    if($key == $m || !empty($t))
    {
        $n[] = $month;
        $t = 1;
    } else {
        $s[] = $month;
    }
}
 
$n = array_merge($n, $s);
 
print_r($n);
 
//Array ( [0] => March [1] => April [2] => May [3] => June [4] => July [5] => August [6] => September [7] => October [8] => November [9] => December [10] => January [11] => February ) 
 

Re: Smart way to sort my 1 dim array

Posted: Mon Feb 01, 2010 4:19 am
by josh
Thats an obscure way to do it. Does the function named setMonth actually do something like "getting the index of the month"? Why not name it getMonthIndex(), or do something obvious like a for loop:

Code: Select all

 
const MARCH = 3;
const DECEMBER = 12;
 
function iterateMonths( $months ) {
 $return=array();
 for( $i = self::MARCH; $i <= self::DECEMBER; $i++ ) {
  array_push($return,$months[$i]);
 }
 return $return;
}
 

Re: Smart way to sort my 1 dim array

Posted: Mon Feb 01, 2010 4:27 am
by papa
Thanks Josh,

With your example Jan and Feb is lost though.

This is the complete code:

Code: Select all

 
 
$cur_month = date('n');
 
$months = array(1=>"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");
 
function setMonth($cur_month)
{
    if($cur_month == 12)
    {   
        return $month = 1;
    } else {
        return $month = $cur_month + 1;
    }
}
 
$m =  setMonth($cur_month);
 
$n = array();
 
foreach($months as $key => $month)
{
    if($key == $m || !empty($t))
    {
        $n[] = $month;
        $t = 1;
    } else {
        $s[] = $month;
    }
}
 
$n = array_merge($n, $s);
 
//print_r($n);
setMonth() is setting current month to +1 if it's not month 12. I'm fetching data 12 months back. So in my SQL statement it also sets year to 2009 and March, instead of Feb 2010.

Re: Smart way to sort my 1 dim array

Posted: Mon Feb 01, 2010 4:37 am
by VladSun

Code: Select all

$months = array(1=>"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");
$startMonth = 3;
 
for ($month = 0; $month < 12; $month ++)
    echo($months[(($month + $startMonth - 1) % 12) + 1]);
 

Re: Smart way to sort my 1 dim array

Posted: Mon Feb 01, 2010 4:39 am
by papa
Cheers!

Re: Smart way to sort my 1 dim array

Posted: Mon Feb 01, 2010 6:05 am
by VladSun
If your array is zero-based (i.e. 0=> January), it is far more simple and clear ;)

Code: Select all

$months = array("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");
$startMonth = 2; // March
 
for ($month = 0; $month < 12; $month ++)
    echo($months[($month + $startMonth) % 12]);

Re: Smart way to sort my 1 dim array

Posted: Mon Feb 01, 2010 7:27 am
by papa
Nice thanks,

I changed the keys to start at 0.

And it's an Oracle DB, not that it matter here though.. :)

Re: Smart way to sort my 1 dim array

Posted: Mon Feb 01, 2010 12:38 pm
by AbraCadaver

Code: Select all

$months = array("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");
 
$cur_month = date('n')-1;
 
$result = array_merge(array_slice($months, $cur_month, count($months)-$cur_month),
                      array_slice($months, 0, $cur_month));

Re: Smart way to sort my 1 dim array

Posted: Tue Feb 02, 2010 3:22 am
by josh
array_slice is definitely better than looping

Re: Smart way to sort my 1 dim array

Posted: Tue Feb 02, 2010 3:30 am
by VladSun
The array_slice() solution is a nice one indeed :)

Though, for my surprise it's more than two times slower than the looping one ...

Code: Select all

define('ITERS', 100000);
 
function microtime_float()
{
    list($usec, $sec) = explode(" ", microtime());
    return ((float)$usec + (float)$sec);
}
 
$months = array("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");
 
 
$startMonth = 2; // March
 
 
$time_start = microtime_float();
 
for ($i = 0; $i < ITERS; $i++)
{
    $nmonths = array_merge
    (
        array_slice($months, $cur_month, count($months)-$startMonth),
        array_slice($months, 0, $startMonth)
    );
}
 
$time_end = microtime_float();
$time = $time_end - $time_start;

echo "$time seconds<br>";
 
 
$time_start = microtime_float();
 
for ($i = 0; $i < ITERS; $i++)
{
    $nmonths = array();
    for ($month = 0; $month < 12; $month ++)
        $nmonths[] = $months[($month + $startMonth) % 12];
}
 
$time_end = microtime_float();
$time = $time_end - $time_start;
 
echo "$time seconds<br>";
 
=>

Code: Select all

1.46927499771 seconds
0.696362018585 seconds
Also, it really depends on how this code is going to be used - I do think one will has to iterate through the generated array sooner or a latter (i.e. the "looping" has to occur )...

Re: Smart way to sort my 1 dim array

Posted: Tue Feb 02, 2010 11:01 am
by AbraCadaver
There is an error in the above code. You left $cur_month in one of the array_slice() calls and it is undefined. It should be $startMonth. Changing this the time is a little better and changing count($months) to 12 is slightly better, though the loop is still faster:

Code: Select all

// array slice with count()
1.96138095856 seconds
 
// array slice without count()
1.34590888023 seconds
 
// loop
0.907220840454 seconds

Re: Smart way to sort my 1 dim array

Posted: Tue Feb 02, 2010 8:25 pm
by josh
I think readability is more important than which one is fastest if called 1/10 Million times.

Re: Smart way to sort my 1 dim array

Posted: Wed Feb 03, 2010 1:45 am
by VladSun
josh wrote:I think readability is more important than which one is fastest if called 1/10 Million times.
Frankly, I really can't see anything not "readable" in my solution. It can't be more "standard" than it is. It's universal - take any other programming language and you'll write it the same way. And it's even more functional:

Problem1: Take the month that is 6 months after the current month and display the 12 months as requested above.
Solution1: The array_slice() solution implemented *as the above one* will fail, if the current month is >= 6. The %12 solution will work without any modifications.

Problem2: Display 8 (or 14, but not 12) months after a specified month
Solution2: The %12 solution needs only a single modification: "for ($month = 0; $month < 8; $month ++)". I've tried some quick fixes for the array_slice() solution without success. I think it will need min/max functions to work.

And finally:

Code: Select all

for ($ix = 0; $ix < $interval; $ix ++)
    echo ($ix + $offset) % $period;
No arrays ...


So, I'd say I totally disagree with you ;)

I don't mean that in this particular case the array_slice() solution is bad - don't get me wrong. I'm just saying that the %$period approach is far more extensible and reusable that the array_slice() approach, which I do think is far more important than *some* readability added.
After all we are developers in first place, and humans in second :P