Re: Sorting year and month
On Mar 2, 2005, at 12:14 AM, John Horner wrote: @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? Yes - when you use ||, it short circuits the expression if the first part is true. Conversely, when you use , it short circuits if the first part is false. sherm-- Cocoa programming in Perl: http://camelbones.sourceforge.net Hire me! My resume: http://www.dot-app.org
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 # } # ]; #
Sorting year and month
Hi, I have a quick question regarding sorting. I have a list of dates and years in the following format: October-2004 December-2004 September-2004 January-2005 November-2004 I need to sort them so the final outcome is: January-2005 December-2004 November-2004 October-2004 September-2004 Of course the list will eventually include all 12 months, but the above is just an example. What is the best way to go about doing this? I'm not too familiar with using sort, but I'm sure that is the way to go. Any help would be appreciated. Thanks, Mark
Re: Sorting year and month
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? Thanks, Mark On Feb 28, 2005, at 1:03 AM, Sherm Pendley wrote: On Feb 28, 2005, at 3:41 AM, Mark Wheeler wrote: I have a quick question regarding sorting. I have a list of dates and years in the following format: October-2004 December-2004 September-2004 January-2005 November-2004 I need to sort them so the final outcome is: January-2005 December-2004 November-2004 October-2004 September-2004 Of course the list will eventually include all 12 months, but the above is just an example. What is the best way to go about doing this? I'm not too familiar with using sort, but I'm sure that is the way to go. Any help would be appreciated. Have a look at Date::Manip - it has date parsing and comparison functions you can use with sort(). Example: #!/usr/bin/perl use warnings; use strict; use Date::Manip; my @dates = qw( October-2004 December-2004 September-2004 January-2005 November-2004 ); my @sorted = sort { Date_Cmp(ParseDate($b), ParseDate($a)); } @dates; for (@sorted) { print $_, \n; } sherm-- Cocoa programming in Perl: http://camelbones.sourceforge.net Hire me! My resume: http://www.dot-app.org