Sorting arrays based on month and year

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
smudge
Forum Contributor
Posts: 151
Joined: Sun May 20, 2007 12:13 pm

Sorting arrays based on month and year

Post by smudge »

Hello again.
I have a simple problem: I need to sort an array of months and years by year (most recent first) then by month (Jan-Dec).
I have tried other ways, but with no luck.

The array being fed into my sorting function is 2 dimensional: each entry has a month and a 2 digit year, both as strings.
Here is my code:

Code: Select all

function sortByMonth($cur,$nxt){  //this works
    global $list_months;//an array filled with 'jan','feb','mar',...
    $mon_inv=array_flip($list_months);
    return ($mon_inv[$cur[0]]<$mon_inv[$nxt[0]])?-1:1;
}

function sortBy2Year($cur,$nxt){  //this works
	//cur and nxt as array('feb','08')
	$y1=intval($cur[1]);
	$y2=intval($nxt[1]);
	return ($y1>$y2)?-1:1;
}

function sortByMonthYear($cur,$nxt){ //this doesn't work
	$mon=sortByMonth($cur,$nxt);
	$year=sortBy2Year($cur,$nxt);
	$out=0;
	if($mon==-1 && $year==-1)
	  $out=-1;
	else if($mon==-1 && $year==1)
	  $out=1;
	else if($mon==1 && $year==-1)
	  $out==-1;
	else if($mon==1 && $year==1)
	  $out=1;
	return $out;
}

function my_unique($arr){ //this works
	//arr is of form array(array('feb','07'),array('jan','08'))
	$out=array();
	for($i=0;$i<count($arr);$i++){
		$month=$arr[$i];
		$m=$month[0];
		$y=$month[1];
		if(in_array($month,$out))
			unset($arr[$i]);
		else
			$out[]=$month;
	}
	return $out;
}

$list_newsletters=my_unique(array_merge($docs_months,$pdfs_months));  //this works
usort($list_newsletters,"sortByMonthYear");//this doesn't work
This seems to work only if the usort is called repeatedly.

Is there a better way to do this that doesn't require calling usort twenty times?
User avatar
Jonah Bron
DevNet Master
Posts: 2764
Joined: Thu Mar 15, 2007 6:28 pm
Location: Redding, California

Post by Jonah Bron »

I'm not entirely sure what you are ordering. An array? A string? Like this?

Code: Select all

array(array('jan', 03), array('mar', 06), array('dec', 98));

Code: Select all

or this?[php]
$str1 = 'jan 03';
$str2 = 'mar 06';
etc...[/php] I'm a little lost
smudge
Forum Contributor
Posts: 151
Joined: Sun May 20, 2007 12:13 pm

Post by smudge »

like this:
array(array('feb','08'),array('jan','07'),...);

I want it to sort this:
may 07
mar 07
jan 08
feb 07
jan 07
feb 08

into this:
jan 08
feb 08
jan 07
feb 07
mar 07
may 07

those are not the actual values. just an example to help clarify.
Sort the most recent year by month, 2nd recent year by month, nth year by month
User avatar
Kieran Huggins
DevNet Master
Posts: 3635
Joined: Wed Dec 06, 2006 4:14 pm
Location: Toronto, Canada
Contact:

Post by Kieran Huggins »

maybe convert them to a timestamp, sort them, then convert back.

strtotime() should do the trick. You may have to prepend a "01 " to the beginning of each string so it doesn't think the 2 digit year is a date.
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

I'd temporarily convert the month names to numbers, multisort it, then convert back.
baileylo
Forum Newbie
Posts: 13
Joined: Sun Sep 30, 2007 12:48 am

Post by baileylo »

Code: Select all

//Sample input
$input[] = array('5','07');
$input[] = array('3','07');
$input[] = array('1','08');
$input[] = array('2','07');
$input[] = array('1','07');
$input[] = array('2','08'); 

//Simple Sort
for($i = 0; $i < count($input); $i++){
  for($j = 0; $j < count($input) - 1; $j++){
    if($input[$j][1] < $input[$j+1][1]){
      $temp = $input[$j];
      $input[$j] = $input[$j+1];
      $input[$j+1] = $temp;
    }else if($input[$j][0] > $input[$j+1][0]){
      $temp = $input[$j];
      $input[$j] = $input[$j+1];
      $input[$j+1] = $temp;
    }
  }
 }
Out of laziness I converted your months to their numeric values. Not hard to right a function to do this. this works perfectly on your data set, might want to test with more data.
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

baileylo: PHP has a built in array_multisort() which is much faster than your pure PHP implementation of bubble sort (probably the worst thing you could possibly implement).
User avatar
Mordred
DevNet Resident
Posts: 1579
Joined: Sun Sep 03, 2006 5:19 am
Location: Sofia, Bulgaria

Post by Mordred »

I think smudge has the better idea of using usort (the fastests way), all other proposed solutions behave like a vacuum cleaner, sorry guys.
smudge, do read more on the correct way of using the callback to usort, then scratch your sortBy...() functions and write a new one.

Trivia: The callback defines the so-called 'starship operator', called so because of its notation: <=> (cool, eh! :) )
It returns -1, 0 or 1. (hint: your callbacks didn't handle the 0 correctly)
Post Reply