Re: Sorting year and month

2005-03-01 Thread Sherm Pendley
On Mar 1, 2005, at 2:48 AM, Mark Wheeler wrote:
Hi Sherm,
That works perfectly. Could you give me a brief rundown on how the 
sort works with Date::Manip, so I can understand what is going on?

On Feb 28, 2005, at 1:03 AM, Sherm Pendley wrote:
my @sorted = sort { Date_Cmp(ParseDate($b), ParseDate($a)); } 
@dates;
I'm not certain how much detail you need, so I'll start at the 
beginning, with sort(). Sort() allows you to provide a block of code 
that's used as a comparison function. Two arguments are passed to that 
function - $a and $b - and the return value should mimic that of = or 
cmp - that is,  0 if $a  $b, 0 if $a == $b, and  0 if $a  $b.

So, suppose we have a list of hashes, like this:
my @garbled = (
{ 'foo'='trouble', 'sort_by'=3 },
{ 'foo'='hubble', 'sort_by'=0 },
{ 'foo'='toil', 'sort_by'=2 },
{ 'foo'='bubble', 'sort_by'=1 },
);
We could sort it according to the sort_by field like this:
my @spell = sort { $a-{'sort_by'} = $b-{'sort_by'} } @garbled;
Note that there's no comma between the comparison function and 
@garbled. If there were, Perl would treat the block as the first 
element in the list to be sorted. Also, $a and $b are magic - you don't 
have to declare them with my() or our(), or shift them off of @_. 
They're just there. Also, strict knows about them, although not in 
detail; you can use an undeclared $a or $b *anywhere*, not just with a 
sort(), without hearing a peep from strict.

So anyway, how's that work with Date::Manip?
The ParseDate() function takes a date in a variety of formats, and 
returns it in a normalized format: mmddhh:mm:ss. Date_Cmp() 
compares two of these normalized date strings, and returns a value 
that's consistent with = or cmp - that is, 0, 0, or 0 - as expected 
by sort.

You *could* simply use cmp to compare these strings - in fact that's 
basically all Date_Cmp() does right now - but the Date::Manip docs 
indicate that the normalized format will be extended at some future 
point, to include various flags such as the time zone. At that point, 
Date_Cmp() will also be updated to take the flags into account, whereas 
cmp will no longer work. So, using Date_Cmp() is optional at the 
moment, but it's more future-proof than cmp.

sherm--
Cocoa programming in Perl: http://camelbones.sourceforge.net
Hire me! My resume: http://www.dot-app.org


Re: Sorting year and month

2005-03-01 Thread Mark Wheeler
Hi Sherm,
Thanks for taking the time to explain it. That makes sense.
Mark
On Mar 1, 2005, at 12:59 AM, Sherm Pendley wrote:
On Mar 1, 2005, at 2:48 AM, Mark Wheeler wrote:
Hi Sherm,
That works perfectly. Could you give me a brief rundown on how the 
sort works with Date::Manip, so I can understand what is going on?

On Feb 28, 2005, at 1:03 AM, Sherm Pendley wrote:
my @sorted = sort { Date_Cmp(ParseDate($b), ParseDate($a)); } 
@dates;
I'm not certain how much detail you need, so I'll start at the 
beginning, with sort(). Sort() allows you to provide a block of code 
that's used as a comparison function. Two arguments are passed to that 
function - $a and $b - and the return value should mimic that of = or 
cmp - that is,  0 if $a  $b, 0 if $a == $b, and  0 if $a  $b.

So, suppose we have a list of hashes, like this:
my @garbled = (
{ 'foo'='trouble', 'sort_by'=3 },
{ 'foo'='hubble', 'sort_by'=0 },
{ 'foo'='toil', 'sort_by'=2 },
{ 'foo'='bubble', 'sort_by'=1 },
);
We could sort it according to the sort_by field like this:
my @spell = sort { $a-{'sort_by'} = $b-{'sort_by'} } @garbled;
Note that there's no comma between the comparison function and 
@garbled. If there were, Perl would treat the block as the first 
element in the list to be sorted. Also, $a and $b are magic - you don't 
have to declare them with my() or our(), or shift them off of @_. 
They're just there. Also, strict knows about them, although not in 
detail; you can use an undeclared $a or $b *anywhere*, not just with a 
sort(), without hearing a peep from strict.

So anyway, how's that work with Date::Manip?
The ParseDate() function takes a date in a variety of formats, and 
returns it in a normalized format: mmddhh:mm:ss. Date_Cmp() 
compares two of these normalized date strings, and returns a value 
that's consistent with = or cmp - that is, 0, 0, or 0 - as expected 
by sort.

You *could* simply use cmp to compare these strings - in fact that's 
basically all Date_Cmp() does right now - but the Date::Manip docs 
indicate that the normalized format will be extended at some future 
point, to include various flags such as the time zone. At that point, 
Date_Cmp() will also be updated to take the flags into account, whereas 
cmp will no longer work. So, using Date_Cmp() is optional at the 
moment, but it's more future-proof than cmp.

sherm--
Cocoa programming in Perl: http://camelbones.sourceforge.net
Hire me! My resume: http://www.dot-app.org


Re: Sorting year and month

2005-03-01 Thread John Horner
I was interested by this question -- and let me say, of course the 
correct answer is, use the module -- I just took the opportunity to 
try learn a bit about more advanced sorting.

The following is of course a very roundabout solution, but it shows 
how you can sort by an arbitrary quality you assign yourself (as you 
might if you wanted to sort the months from financial year to 
financial year where April might be 1 and March 12) and how to 
sub-sort.

I'd appreciate your comments.
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;
use Data::Dumper;
my %months = ( Jan = 1, Feb = 2, Mar = 3, Apr = 4 );
## Assign values to the month names,
## I'm too lazy to do the whole 12.
my @dates = qw(
  Apr-2005 Feb-2001 Mar-2001
  Jan-2004 Jan-2005 Mar-2005
  Feb-2003 Mar-2003 Apr-2003
  Mar-1999 Apr-1999 Feb-2002
);
## randomly chosen dates in random order
my @data = ();
for ( @dates ) {
my ( $m, $y ) = split( '-', $_ );
push( @data, { year = $y, month = $m } );
}
## build AoH from dates
@data = sort {
$a-{year} = $b-{year}
  ||
$months{ $a-{month} } = $months{ $b-{month} }
} @data;
## only if the years are equal does the second sort take place, is that right?
print Dumper( [EMAIL PROTECTED] );
## seems to work:
# $VAR1 = [
#   {
# 'month' = 'Mar',
# 'year' = 1999
#   },
#   {
# 'month' = 'Apr',
# 'year' = 1999
#   },
#   {
# 'month' = 'Feb',
# 'year' = 2001
#   },
#   {
# 'month' = 'Mar',
# 'year' = 2001
#   },
#   {
# 'month' = 'Feb',
# 'year' = 2002
#   },
#   {
# 'month' = 'Feb',
# 'year' = 2003
#   },
#   {
# 'month' = 'Mar',
# 'year' = 2003
#   },
#   {
# 'month' = 'Apr',
# 'year' = 2003
#   },
#   {
# 'month' = 'Jan',
# 'year' = 2004
#   },
#   {
# 'month' = 'Jan',
# 'year' = 2005
#   },
#   {
# 'month' = 'Mar',
# 'year' = 2005
#   },
#   {
# 'month' = 'Apr',
# 'year' = 2005
#   }
# ];
#