Smart way to sort my 1 dim array

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
User avatar
papa
Forum Regular
Posts: 958
Joined: Wed Aug 27, 2008 3:36 am
Location: Sweden/Sthlm

Smart way to sort my 1 dim array

Post 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 ) 
 
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Re: Smart way to sort my 1 dim array

Post 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;
}
 
User avatar
papa
Forum Regular
Posts: 958
Joined: Wed Aug 27, 2008 3:36 am
Location: Sweden/Sthlm

Re: Smart way to sort my 1 dim array

Post 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.
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

Re: Smart way to sort my 1 dim array

Post 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]);
 
There are 10 types of people in this world, those who understand binary and those who don't
User avatar
papa
Forum Regular
Posts: 958
Joined: Wed Aug 27, 2008 3:36 am
Location: Sweden/Sthlm

Re: Smart way to sort my 1 dim array

Post by papa »

Cheers!
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

Re: Smart way to sort my 1 dim array

Post 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]);
There are 10 types of people in this world, those who understand binary and those who don't
User avatar
papa
Forum Regular
Posts: 958
Joined: Wed Aug 27, 2008 3:36 am
Location: Sweden/Sthlm

Re: Smart way to sort my 1 dim array

Post by papa »

Nice thanks,

I changed the keys to start at 0.

And it's an Oracle DB, not that it matter here though.. :)
User avatar
AbraCadaver
DevNet Master
Posts: 2572
Joined: Mon Feb 24, 2003 10:12 am
Location: The Republic of Texas
Contact:

Re: Smart way to sort my 1 dim array

Post 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));
mysql_function(): WARNING: This extension is deprecated as of PHP 5.5.0, and will be removed in the future. Instead, the MySQLi or PDO_MySQLextension should be used. See also MySQL: choosing an API guide and related FAQ for more information.
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Re: Smart way to sort my 1 dim array

Post by josh »

array_slice is definitely better than looping
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

Re: Smart way to sort my 1 dim array

Post 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 )...
There are 10 types of people in this world, those who understand binary and those who don't
User avatar
AbraCadaver
DevNet Master
Posts: 2572
Joined: Mon Feb 24, 2003 10:12 am
Location: The Republic of Texas
Contact:

Re: Smart way to sort my 1 dim array

Post 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
mysql_function(): WARNING: This extension is deprecated as of PHP 5.5.0, and will be removed in the future. Instead, the MySQLi or PDO_MySQLextension should be used. See also MySQL: choosing an API guide and related FAQ for more information.
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Re: Smart way to sort my 1 dim array

Post by josh »

I think readability is more important than which one is fastest if called 1/10 Million times.
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

Re: Smart way to sort my 1 dim array

Post 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
There are 10 types of people in this world, those who understand binary and those who don't
Post Reply