Sorting (All Sorts of Sorts)
From JmPm
Sorting
- Simple Sorts
- Orchish
- Schwartzian Transform
- Guttman Rosler Transform
- My example of sorting (which is not really ST)
- Modules
- Sort::Maker
Simple Sorts
• Sort Subroutines
• $a $b
• Routines that give < = > zero
• Numeric
@sorted = sort {$a <=> $b} @unsorted
• Descending
@sorted = sort {$b cmp $a} @unsorted;
• Case-insensitive
@sorted = sort {lc $a cmp lc $b} @unsorted;
• Element-length sort:
@sorted = sort {lenth $a <=> length $b} @unsorted;
• Sort hash by value
@sorted = sort { $hash{$b} cmp $hash{$a} } @unsorted;
• More complex functions
@sorted = sort {
(split ':', $a, 2)[0] cmp split ':', $b, 2)[0]
} @pw_lines;
• Mutiple subkey sorts
@sorted = sort {
&key1($a) cmp &key1($b)
||
&key2($b) <=> &key2($a)
||
&key3($a) cmp &key3($b)
}@unsorted
The Orcish Maneuver (OM)
keys my %or_cache = @unsorted;
@sorted = sort {
($or_cache{$a} ||= KEY($a))
cmp
($or_cache{$b} ||= KEY($b))
} @unsorted;
The Schwartzian Transform
@sorted =
map { $_->[0] }
sort { $a->[1] cmp $b->[1] }
map { [$_, foo($_)]
} @unsorted;
@sorted=
map { pop @$_ }
sort{ $a->[0] <=> $b->[0] || $a->[1] cmp $b->[1] }
map { [tr/eE/eE/,$_] }
@words;
- First map the array to an array of arrays
- The inner array is [original,output of function]
- Then sort the second member of the inner array
- Then move the first part of the inner array to the sorted array
Guttman Rosler Transform (GRT)
my @sorted=map { substr($_,4) }
sort
map { pack("LA*",tr/eE/eE/,$_) }
@words;
My Sort
@sub field is an aoa [char to sort by, rest of the data]
sort by the [0] place in each sub-array
letters come first then numbers (not like in ASCII)
lower case come before uppercase but are dispersed between the uppercase i.e. (aAbBcC....yYzZ0123456789)
sub by_subfield{
unless ( $a->[2] cmp $b->[2]){ #falls through when it is the same letter or any number
if ($a->[0] =~ /\d/){
$a->[0] cmp $b->[0] ;#sort numbers normally
}
else {$b->[0] cmp $a->[0]#sort within each letter lc first(reverse of ASCII)
}
}
}
@sorted = map{$_->[0],$_->[1]} # get rid of helper field
sort by_subfield
map{[$_->[0],$_->[1],$_->[0]=~ /\d/ ? '}' :lc($_->[0])]
[orig 0,orig 1,orig 0 as lowercase or '}' if it is a number because that is highest]
} @subfields;
Sort::Maker
• Sort style
my $plain_sorter = make_sorter( qw( plain ) ... ) ;
my $orcish_sorter = make_sorter( orcish => 1 ... ) ;
my $st_sorter = make_sorter( 'ST', 1, ... ) ;
my $GRT = make_sorter( 'GRT', ... ) ;
• Key attributes
ascending (default) descending
case (default) no_case
signed unsigned signed_float (default) unsigned_float fixed varying
Sort Pragma
• use sort 'stable'; # guarantee stability
• use sort '_quicksort'; # use a quicksort algorithm
• use sort '_mergesort'; # use a mergesort algorithm
• use sort 'defaults'; # revert to default behavior
• no sort 'stable'; # stability not important
• use sort '_qsort'; # alias for quicksort
my $current = sort::current(); # identify prevailing algorithm
References
- Programming Perl pp. 740,789
- Perl Cookbook pp138-143
- Perl Best Practices
- http://en.wikipedia.org/wiki/Schwartzian_transform
- http://www.perlmonks.org/?node=145659
- http://www.perlfect.com/articles/sorting.shtml
- http://sysarch.com/Perl/sort_paper.html
- http://perldoc.perl.org/functions/
• Map
%hash = map { getkey($_) => $_ } @array;
@words = map split, @phrases;
• Pack
pack TEMPLATE,LIST
