Page 1 of 1

Sorting arrays based on month and year

Posted: Sat Jan 05, 2008 7:44 am
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?

Posted: Sat Jan 05, 2008 11:47 am
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

Posted: Sat Jan 05, 2008 10:08 pm
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

Posted: Sat Jan 05, 2008 10:32 pm
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.

Posted: Sat Jan 05, 2008 11:37 pm
by Ambush Commander
I'd temporarily convert the month names to numbers, multisort it, then convert back.

Posted: Sun Jan 06, 2008 4:10 am
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.

Posted: Sun Jan 06, 2008 11:47 am
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).

Posted: Sun Jan 06, 2008 12:26 pm
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)