Re: Sorting year and month
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
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
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 # } # ]; #