On Fri, May 29, 2009 at 11:51, John W. Krahn <jwkr...@shaw.ca> wrote: > Bryan Harris wrote: >> >> Let's say I have a bunch of lines of data in an array, @a: >> >> car 72 >> car 55 >> truck 31 >> bike 2 >> car 12 >> truck 16 >> van 97 >> car 64 >> >> ... and I want to sort them so that the trucks are first, then the vans, >> the bikes are third, cars are next, and everything else sorted >> alphabetically at the end. >> >> I started down this route: >> >> @a = sort { >> if ($a =~ /^truck/ && $b =~ /^truck/) { 0 } >> elsif ($a =~ /^truck/ && $b =~ /^van/) { -1 } >> ... } @a; >> >> ... but that quickly breaks down. Then I thought, what about this?: >> >> @a = ( grep { /^truck/ } @a, grep { /^van/ } @a, grep { /^bike/ } @a, grep >> { /^cars/ } @a, sort grep { !/^(truck|van|bike|cars)/ } @a); >> >> ... which seems to work, but looks clunky, feels like it'd be slow, and >> doesn't scale well if my list of 5 things were to become 75. >> >> How is this kind of thing usually done? > > > my %order = ( > truck => 0, > van => 1, > bike => 2, > car => 3, > '' => 4 > ); > > my $regex = qr/^(truck|van|bike|car)/; > > my @sorted = sort { $order{ ( $a =~ $regex )[ 0 ] } <=> $order{ ( $b =~ > $regex )[ 0 ] } || $a cmp $b } @a; snip
This is begging for a Schwartzian Transform[1]: #!/usr/bin/perl use strict; use warnings; my %order = ( truck => 1, van => 2, bike => 3, car => 4, ); my @data; while (<DATA>) { chomp; push @data, [split]; } #sort by vehicle type first and number second if they are the same type my @sorted = map { $_->[1] } sort { $a->[0] <=> $b->[0] or $a->[1][1] <=> $b->[1][1] } map { [ ($order{$_->[0]} || 100), $_ ] } @data; print "unsorted:\n", format_data(@data), "\nsorted:\n", format_data(@sorted); sub format_data { my $string; for my $rec (@_) { $string .= sprintf "%6s %2d\n", @$rec; } return $string; } __DATA__ car 72 car 55 truck 31 bike 2 car 12 other 15 other 6 truck 16 van 97 car 64 1. http://en.wikipedia.org/wiki/Schwartzian_Transform -- Chas. Owens wonkden.net The most important skill a programmer can have is the ability to read. -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/