in reply to sort an array

Well first of all that regex won't quite work, because the .+ will eat up all the digits, up the last one before the #. To prevent this, use (.+?).

Now then:

@sorted = sort { my @a = $a =~ /^(.+?)(\d+)#(\d+)$/; my @b = $b =~ /^(.+?)(\d+)#(\d+)$/; $a[1] <=> $b[1] or $a[2] <=> $b[2] or $a[0] cmp $b[0] } @unsorted;
However, that's rather inefficient due to the fact that any given string gets parsed each time it's used in a comparison. Using the Schwartzian Transform is one way to alleviate this:
@sorted = map { $_->[0] } sort { $a->[2] <=> $b->[2] or $a->[3] <=> $b->[3] or $a->[1] cmp $b- +>[1] map { [ $_, /^(.+?)(\d+)#(\d+)$/ ] } @unsorted;

Maybe that's even easier to make sense of.


You could get really fancy, and use a module for this. One that comes to (my) mind is Sort::Fields. Here's one way you could do it:
use Sort::Fields; my $sorter = make_stable_fieldsort( '(\d+)#', [ '2n', '3n', '1' ] ); my @sorted = $sorter->( @unsorted ); # voila
We're building the house of the future together.

Replies are listed 'Best First'.
Re^2: sort an array
by myffy (Acolyte) on Mar 19, 2006 at 07:53 UTC
    Thanks JD,

    You're awesome. I tried both of them. The second one had a slight problem (the # needed to be escaped). They both do exactly what I need. I understand the first one better, so I might go with that one.

    myffy

      If you have trouble understanding the second one, you should look up the phrase "Schwartzian transform", when you have some free time, and read up on the technique. Becomming comfortable with this is something that will help you to think like an advanced Perl programmer. It's not just the technique itself, but the paradigms that it represents, notably, the idea of transforming a list, which is a very generally applicable thing and something Perl is very good for doing, so that it is something every really advanced Perl programmer needs to understand.

      However, ad interim, you should use the technique that you understand already.


      Sanity? Oh, yeah, I've got all kinds of sanity. In fact, I've developed whole new kinds of sanity. Why, I've got so much sanity it's driving me crazy.
      the # needed to be escaped

      I don't believe you. Pound signs never need to be escaped in regexes, and it shouldn't make any difference if they are or not. I invite you to show us your exact code — the one that behaves differently depending on whether the pound sign is escaped or not.

      We're building the house of the future together.
        Sorry, but you're wrong.
        $_ = "SomecomplexREhereandthenafoobar"; if (/Some complex RE here and then a # to ignore/x) { print "Escaping that # would have mattered\n"; }