home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.lang.perl
- Path: sparky!uunet!psinntp!balltown!rodney
- From: rodney@cabot.balltown.cma.COM (Rodney Peck)
- Subject: Re: Looking for a "numerical/alpha" sort routine.
- Message-ID: <1992Dec24.033259.666@cabot.balltown.cma.COM>
- Organization: New York State Institute for Sebastian Cabot Studies
- References: <1992Dec23.193120.25893@pool.info.sunyit.edu>
- Date: Thu, 24 Dec 1992 03:32:59 GMT
- Lines: 64
-
- buck@pool.info.sunyit.edu (Jesse Buckley) writes:
- : Does anyone have a sort/compare routine that will work for numerical
- : alpha data? For example, if I have 1, 2, 3a, 3b, 3c, I want them sorted
- : that way. Right now the <=> compare ignored the letters after the
- : numbers. Thanks.
-
- Well, I played with this question for about an hour and came up with this:
-
- $a cmp $b unless $a <=> $b;
-
- It's efficient because the cmp is only called if they are numerically
- equal. Otherwise, the value of the numeric compare is returned.
-
- Orginally, I spent a lot of time trying to get just the characters and
- then compare them with cmp, but since the numbers are equal, the
- beginning of the strings will be the same and cmp will properly rank
- them even though the numbers are still on the front of the string.
-
- However, since I spent all that time working on this, and figured out
- a few nifty things that other people might want to study or whatever.
-
- Here's the general idea I came up with orginally before trying to
- remove the local variables:
- sub newcmp {
- # works like <=>, but also deals with trailing letters
- # use the <=> first, but it lies about things being
- # equal so check with a cmp on the trailing letters
-
- local ($ans) = ($a <=> $b);
- if ($ans == 0)
- {
- local($aa, $bb);
- ($aa) = ($a =~ /\d*(\D*)/);
- ($bb) = ($b =~ /\d*(\D*)/);
- $ans = ($aa cmp $bb);
- }
- $ans;
- }
-
- Here are four different one liners trying to get the letters away
- from the numbers before I realized that the numbers would be the same
- if the numbers compared equally. It might be worth someone's while
- to read them and figure out the different intentions. The big thing
- was to avoid local variables, and to reduce size.
-
- "$a:$b" =~ /\d*(\D*):\d*(\D*)/, $1 cmp $2 unless $a <=> $b;
-
- @_ = "$a:$b:" =~ /\d(\D):/g, shift cmp shift unless $a <=> $b;
-
- split(/:\d+/,":$a:$b", shift, shift cmp shift unless $a <=> $b;
-
- ($junk,@_) = split(/:\d+/,":$a:$b"), shift cmp shift unless $a <=> $b;
-
- And finally, the obJAPH using the new sort routine:
-
- #----
- #!/bin/perl
- $_= '2bn3ap1aj3cr3dl2h 2eh3e 4cc1bu2gr3be4ah';
- $_.='4ba4dk2aa4ee2fe1dt2co1cs2dt1e 4fr9a\9bn';
- while(($a,$b,$_)=/^(..)(.)(.*)$/) {$a{$a}=$b;}
- grep($f.=$a{$_},sort{$a cmp $b unless $a<=>$b}
- keys%a); eval("print \"$f\"");
- #----
- Rodney
-