Christopher Yee Mon wrote:
> I have an array of strings whose members consist of a number followed by 
> a comma followed by a text string
> 
> e.g.
> 1,fresh
> 2,testurl
> 
> I want to sort by descending numerical order according to the number 
> part so I made this sort subroutine
> 
> sub by_counter_field {
>   my($a, $b) = @_;
>   $a =~ s/^(.*?),.*/$1/g;
>   $b =~ s/^(.*?),.*/$1/g;
> 
>   if ($a > $b) { -1 } elsif ($a < $b) { 1 } else { 0 }
> }
> 
> and sorted it with
>   sort by_counter_field @array;
> and it didn't work.
> 
> I've also tried replacing
>   if ($a > $b) { -1 } elsif ($a < $b) { 1 } else { 0 }
> with
>   $b <=> $a
> and it still didn't work.
> 
> I also tried this
>   sort { ($b =~ /(.*?),.*/)[0] <=> ($a =~ /(.*?),.*/)[0] } @array;
> and it didn't work either.
> 
> I can't figure it out for the life of me
> 
> Any assistance would be deeply appreciated.

You misunderstand the way $a and $b work. It is an ugly mechanism, but when
'sort' calls your comparison subroutine the global variables $a and $b are
already set to the two values to be compared. What is even more hazardous is
that if you modify them as you have tried to do with s/// you will change the
values in the list you are sorting.

If the derivation is non-trivial then I usually write code that evaluates
lexical variables $aa and $bb from $a and $b, and then simply compare them with
<=> or 'cmp' as appropriate.

The code below is a working rewrite of your program. I hope it helps.

Rob


use strict;
use warnings;

no warnings 'qw';

my @data = qw/
  99,tomato
  12,pear
  1,fresh
  2,testurl
  16,summary
  0,zero
  76,trombones
  88,fatso
/;

sub by_counter_field {

  my $aa = $a =~ /^(\d+)/ ? $1 : 0;
  my $bb = $b =~ /^(\d+)/ ? $1 : 0;

  $bb <=> $aa;
}

my @sorted = sort by_counter_field @data;

print map "$_\n", @sorted;

-- 
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/


Reply via email to