Jump to content
xisto Community
Sign in to follow this  
iGuest

Day_sort() Sort an array by day

Recommended Posts

If it wasn't for vujsa and HandyPHP.com, or the discussion over at Xisto.com.

 

I would have had no reason to make this function more flexible and act more like a PHP function. So this is why I have done this, though I would have contributed it to Xisto.com, I was not a member over there nor does it benefit me in anyway. None of the code has been taken from HandyPHP.com. It's a complete rewrite in a way I felt works better for most people, it could do with better error handling though, but that can be discussed here if needs be.

 

So here it is:

 

day_sort

 

(To use this function needs: PHP 4 or PHP 5. It is not part of PHP)

day_sort -- Sort an array by day of the week.

 

Description

 

bool day_sort ( array &array [, int sort_flag[, int order_flag ]] )

 

This function sorts an array that is prefixed by day of the week from Sunday to Monday including abbreviated days when function has completed.

 

????[/tab]Note: This function assigns new keys for the elements in array. It will remove any existing keys you may have assigned, rather than just reordering the keys.

 

Returns TRUE on success or FALSE on failure.

 

Function day_sort() source

 


{

define('__FUNCTION__', 'day_sort');

}

$argc = func_num_args();

if ($argc < 1)

{

echo "\n".'<p><strong>Warning linenums:0'>function day_sort(&$array = NULL, $sort_flag = SORT_REGULAR, $order_flag = SORT_ASC){ if (!defined('__FUNCTION__')) { define('__FUNCTION__', 'day_sort'); } $argc = func_num_args(); if ($argc < 1) { echo "\n".'<p><strong>Warning:</strong> <em>'.__FUNCTION__.'()</em> expects at least <em>1</em> parameter, <em>'.$argc.'</em> given.</p>'."\n"; return false; } if (!is_array($array)) { echo "\n".'<p><strong>Warning:</strong> <em>'.__FUNCTION__.'()</em> expects parameter <em>1</em> to be an <em>array</em>, <em>'.gettype($array).'</em> given.</p>'."\n"; return false; } if (count($array) < 2) { return true; } if (!is_int($sort_flag)) { echo "\n".'<p><strong>Warning:</strong> <em>'.__FUNCTION__.'()</em> expects parameter <em>2</em> to be <em>integer</em>, <em>'.gettype($sort_flag).'</em> given.</p>'."\n"; return false; } else { switch($sort_flag) { // For PHP > 4.3 // case SORT_LOCALE_STRING: // case 5: case SORT_STRING: case 2: case SORT_NUMERIC: case 1: case SORT_REGULAR: case 0: break; default: $sort_flag = 0; break; } } if (!is_int($order_flag)) { echo "\n".'<p><strong>Warning:</strong> <em>'.__FUNCTION__.'</em> expects parameter <em>3</em> to be <em>integer</em>, <em>'.gettype($order_flag).'</em> given.</p>'."\n"; return false; } else { switch($order_flag) { case SORT_ASC: case 4: case SORT_DESC: case 3: break; default: $order_flag = 4; break; } } if ($argc > 3) { echo "\n".'<p><strong>Warning:</strong> <em>'.__FUNCTION__.'()</em> expects at most <em>3</em> parameters, <em>'.$argc.'</em> given.</p>'."\n"; return false; } $days_pattern = array('/^sun(day)?/i','/^mon(day)?/i','/^tue(sday)?/i','/^wed(nesday)?/i','/^thu(rsday)?/i','/^fri(day)?/i','/^sat(urday)?/i'); $replacements = array(' ! ',' !! ',' !!! ',' !!!! ',' !!!!! ',' !!!!!! '," !!!!!!! "); $tmp_array = array_map('ltrim', $array); $tmp_array = array_values($tmp_array); for ($i = 0, $j = count($days_pattern); $i < $j; $i++) { for ($k = 0, $m = count($tmp_array); $k < $m; $k++) { if (preg_match($days_pattern[$i],$tmp_array[$k])) { $replaced = preg_replace($days_pattern, $replacements, $tmp_array); break; } } } if (!array_multisort($replaced, $order_flag, $sort_flag, $array)) { return false; } $array = array_values($array); return true;}

[tab]Note: This function has not been tested with the int sort_flag being set yet. It is only there for when I expand this function.

 

Example 1. day_sort() example

 

<?php$days_to_sort = array('tuesday34','nottoday','fri382','monday1234','thu384','string_key' => 'Sunday23402', 'su32');$tmp_str = '';day_sort($days_to_sort);foreach($days_to_sort as $key => $value){	$tmp_str .= 'days_to_sort['.$key.'] = '.$value."\n";}echo $tmp_str;?>
The above example will output:

 

days_to_sort[0] = Sunday23402days_to_sort[1] = monday1234days_to_sort[2] = tuesday34days_to_sort[3] = thu384days_to_sort[4] = fri382days_to_sort[5] = nottodaydays_to_sort[6] = su32
The days_to_sort have been sorted by Sunday to Saturday order and those which aren't day names get sorted after.

 

The optional second parameter sort_flag may be used to modify the sorting behavior. For more information on sort_flag please visit PHP: sort - Manual

 

The option third parameter order_flag may be used to modify the order behavior. For more information on order_flag please visit PHP: array_multisort - Manual

 

Warning

Be careful when sorting arrays with mixed typed values because day_sort() can produce unpredictable results.

 

About the code

 

It has been brought to my attention that this code maybe hard for everyone to follow so I will go over it.

 

function day_sort(&$array = NULL, $sort_flag = SORT_REGULAR, $order_flag = SORT_ASC)
This is where we have created our function, it takes 3 parameters but only the first parameter is needed and it must be a reference to an array which means the array must come from a variable e.g. $var = array('something'); day_sort($var); because we are altering the variable itself and returning TRUE on success or FALSE on failure, so we can also check whether this function performed correctly or not.

 

if(!defined('__FUNCTION__'))	{		define('__FUNCTION__', 'day_sort');	}

__FUNCTION__ did not exist till PHP 4.30, I've tried my best to make sure this is PHP 4 compatible, this is just a simple workaround for this.

 

$argc = func_num_args();
Stores the number of arguments sent to the function. $argc stands for argument count.

 

From then on the code should be self explanatory, it's just simple error checking until we get to the switch statements which I'll explain. If you read the Warning messages, it'll explain more about what those checks do.

 

Brief explanation:

Must have at least 1 argument.

First parameter must be an array

If there's only 1 item in the array, there's no reason to sort.

Second parameter must be an integer

Third parameter must be an integer

If there's more than 3 parameters, we've sent too many arguments.

Now all the switch does is make sure that the integers correspond with what has been defined already, and if not, we give it the default values SORT_REGULAR and SORT_ASC.

 

$days_pattern = array('/^sun(day)?/i','/^mon(day)?/i','/^tue(sday)?/i','/^wed(nesday)?/i','/^thu(rsday)?/i','/^fri(day)?/i','/^sat(urday)?/i');
This creates our days_pattern, which is case-insensitive. It works with either 3 letter abbreviated day names or whole names. e.g. Sun or tuesday, etc.

 

$replacements = array(' ! ',' !! ',' !!! ',' !!!! ',' !!!!! ',' !!!!!! ',' !!!!!!! ');
This is what we will replace our day names with, I chose this characters because they come before any alphanumeric character and it's just after space, I also use space to make sure it's seperated for easier ordering as I left trim everything in the array to remove space characters.

 

$tmp_array = array_map('ltrim', $array);
Removes leading space characters and stores the results in a temporary array, since we passed an array by reference if we changed it, those changes will affect the referenced array, so we don't want to change it till it's completed the function.

 

$tmp_array = array_values($tmp_array);
Changes all array names/keys to numbers, maintaining the value positions.

 

Next we have the for loop with another for loop nested inside, what happens is we create an array called $replaced, which changes prefixed days to one of the corresponding replacements, if no replacement is need, it will just store the string without changes.

 

if (!array_multisort($replaced, $order_flag, $sort_flag, $array))	{		return false;	}

This sorts the array, and updates $array, if it fails, no changes are made and it returns false.

 

$array = array_values($array);
Does the same as explained in $tmp_array = array_values($tmp_array); but for our referenced $array.

 

Function completed true is returned and the array we passed has been updated.

 

Things to discuss

 

Should array keys be preserved?

 

If so, it's possible to do this, though I may need to add another parameter to the function to allow it.

 

Should prefixed day strings and non-day strings in the array be seperated or mixed?

 

The main reason why I'm thinking this is the ordering, imagine the days at the top SORT_ASC ordered, then the non-days after it SORT_ASC ordered, that's how it would be with just setting SORT_ASC.

 

But what if you would like to reverse the ordering for days only, or non-days? and place days either before the non-days or after the non-days. Maybe showing an example would explain this better but only if it's requested will I do that.

 

And my last idea is, should we order it even further so that abbreviated names come before whole names, etc. Doesn't matter, what I mean is, should they be grouped seperately too, and can also be ordered seperately?

 

Well thanks for the opportunity to do this, and thanks to vujsa, Xisto.com and HandyPHP.com.

 

Cheers,

 

MC

Share this post


Link to post
Share on other sites

This is a really nice function mastercomputers.

I'm kind of glad to see that your base method is generally the same as mine. What I mean to say is that your central sorting method is done with pattern replacements and then sort the original array by the values of the second array. Other than that, it is completely different except that it returns a nicely sorted array of data.

You pointed out a flaw in my original code which in certain situations would have missorted the data. I have modified the code to perform more consistantly but the numeric method I used could still cause problems.

I like the $days_pattern method that you used with the regular expressions which greatly reduces the overall size of both the search and replace arrays which should generally increase the effiecency of the script.

You had asked about whether or not to preserver array keys and allow for sub-sorting. I'm not sure what is best here. Adding further flexability to the script could also make it more difficult for users to use the function. Since more flexability usually results in additional parameters being entered by the user or at least more options for the user to consider, the user could be overwhelmed by options.

It could be argued that the user could run additional functions on the array after the function is done but if the user was capable of these operations then they should be able to manipulate a more complex function.

I can't believe that in just 2 days this piece of code has been rewritten 4 times on 4 different websites.
BuffaloHelp wrote a script that perform this action which I rewrote for him to make it more efficient. I then modified that script to be more flexable and eventually converted it to a function which I submitted to Handy PHP. This newest version again has increased the effciency and effectiveness of the task.

So I guess this is the 5th version or 3rd generation of the idea. Things happen so fast on the web. :P

Anyway, I'm glad to see that an interest has been taken in this subject. I guess Handy PHP has managed to fulfill one of its goals only after a month of existence.

Thanks for the wonderful post mastercomputers.

vujsa

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×
×
  • Create New...

Important Information

Terms of Use | Privacy Policy | Guidelines | We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.