(jeffa) Re: Helping with sorting
by jeffa (Bishop) on Apr 02, 2003 at 01:41 UTC
|
use strict;
use warnings;
my @array = qw(2aa 2ba 12kf 9cn 9vn 21sg);
my @sorted =
map { join('',@$_) }
sort { $b->[0] <=> $a->[0] or $a->[1] cmp $b->[1] }
map { /(\d+)(\w+)/;[$1,$2] } @array
;
print "$_\n" foreach @sorted;
__END__
21sg
12kf
9cn
9vn
2aa
2ba
Update: be sure and read japhy's Resorting to Sorting. Especially
the part about the Guttman Rosler transforms. (i'll leave that implementation of this
particular problem as an exercise for another monk ;))
Update2: just noticed that the map after the sort could be written more consisely as:
map { [/(\d+)(\w+)/] } @array
Update3: fixed typo (s/b->\[1/a->[1/) ...
thanks Enlil :)
jeffa
L-LL-L--L-LL-L--L-LL-L--
-R--R-RR-R--R-RR-R--R-RR
B--B--B--B--B--B--B--B--
H---H---H---H---H---H---
(the triplet paradiddle with high-hat)
| [reply] [d/l] [select] |
|
|
Thanks to all! I've not only solved the problem I was facing but I'm also learning a lot =)
| [reply] |
|
|
I can't make out where to apply your update3 in your code...if it at all applies to the problem produced in the output "9cn", should be "9nc". Update4?? :)
Chris
| [reply] |
|
|
| [reply] [d/l] [select] |
Re: Helping with sorting
by Enlil (Parson) on Apr 02, 2003 at 02:03 UTC
|
Heres another way to do it. Though it will give warnings with -w or the warnings pragma. use strict;
my @array = qw(2aa 2ba 12kf 9cn 9vn 21sg);
my @sorted = sort {$b <=> $a || $b cmp $a } @array;
print $_,$/ foreach @sorted;
update: the above does both (letters and numbers) in descending order what I think the OP wanted was descending numbers ascending letters. so the following should work: my @array = qw(2aa 2ba 12kf 9cn 9vn 21sg);
my @sorted = sort {$b <=> $a || $a cmp $b } @array;
print $_,$/ foreach @sorted;
-enlil | [reply] [d/l] [select] |
|
|
Wow! (This is the kind of feeling you don't have very often) This solution is really graceful, simple and straight.
Enlil played at least three very neat tricks here:
- He forced the number portion to be extracted and compared. (this gives some warnings, but compare to the elegance he showed us in this one liner, those warnings are really nothing)
If you really want to avoid the warnings, do this:
my @sorted = sort {($b =~ /(\d*)/)[0] <=> ($a =~ /(\d*)/)[0] || $a cmp
+ $b} @array;
- That || triggered the second condition to be evaluated, if the first condition evaluates to false, two elements have the same number portion are ordered by the string as a whole.
- If two elements have the same number portion, then logically, to order them by the string portion following the number portion results the same sequence as to order by the whole string.
| [reply] [d/l] |
|
|
There's just a minor problem with this - granted the sort works with the data supplied. How about text with leading zeros?
2ah
02bl
01hz
I guess that to answer the question of leading zeros, we need to know what the specified requirements are. Still, it's another test scenario for you. | [reply] [d/l] |
|
|
Note: This will only work because the numbers are before the letters. If the letters were first, the numeric comparison would be a no-op.
------ We are the carpenters and bricklayers of the Information Age. Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement. Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.
| [reply] |
Re: Helping with sorting (natural)
by tye (Sage) on Apr 02, 2003 at 06:31 UTC
|
I like several methods found under natural sort. I'll throw together a new one since I haven't done such in a while:
my @array = qw( 2aa 2ba 12kf 9cn 9vn 21sg );
my @idx= do {
my @key = @array;
s[(\d+)][ pack "N", $1 ]ge for @key;
sort { $key[$a] cmp $key[$b] } 0..$#key;
};
my @sorted= @array[@idx];
print "@sorted\n";
outputs
2aa 2ba 9cn 9vn 12kf 21sg
- tye | [reply] [d/l] [select] |
Re: Helping with sorting
by tekkie (Beadle) on Apr 02, 2003 at 15:12 UTC
|
On a side note, I couldn't help but notice that these lines probably aren't doing what you think:
my @sorted = join("\n", sort {$b <=> $a} @array);
print foreach @sorted;
What it looks like you want is for @sorted to be a list of your sorted values, which at the moment, it's not...
When you use join(), it returns a single scalar with your list values delimited by the characters you specify.
Try:
my @array = qw(2aa 2ba 12kf 9cn 9vn 21sg);
my @sorted = join("\n", sort {$b <=> $a} @array);
print $#sorted; # Prints the index of the last element in the array
@sorted = sort {$b <=> $a} @array;
print $#sorted;
And you'll see what I mean. | [reply] [d/l] [select] |
Re: Helping with sorting
by cLive ;-) (Prior) on Apr 02, 2003 at 17:10 UTC
|
my @array = qw(2aa 2ba 12kf 9cn 9vn 21sg);
my @sorted = sort { $a.$b =~ /(\d+)([a-z]+)(\d+)([a-z]+)/;
$1 <=> $2; $3 cmp $4;
} @array;
print join "\n", @sorted;
cLive ;-) | [reply] [d/l] |
Re: Helping with sorting
by sfink (Deacon) on Apr 03, 2003 at 05:31 UTC
|
For YAWWTDI (Yet Another Wrong Way To Do It):
my @sorted = sort { sprintf("%010d%s",$a,$a) cmp sprintf("%010d%s",$b,
+$b) } @array;
Except that, as noted elsewhere, you are strangely doing a descending numerical sort with an ascending alphabetic sort. So we need to flip around one of those sorts. Easy enough, if you don't mind limiting your numeric range a little bit:
my @sorted = sort { sprintf("%08d%s",99999999-$a,$a) cmp sprintf("%08d
+%s",99999999-$b,$b) } @array;
or, better but still quite Wrong:
my @sorted = sort { sprintf("%010u%s",-$a,$a) cmp sprintf("%010u%s",-$
+b,$b) } @array;
| [reply] [d/l] [select] |