A perl idiom of exceeding power and grace, the Schwartzian
transform is a method for sorting a data structure on an arbitrary
key efficiently1 and with a minimum amount of perl code.
The classic ST always takes the form of
map { } sort { } map { }
but,
in general, any sequence of
cascaded maps is
considered to be
a Schwartzian transform. The
canonical ST
2 is
@new = map { $_->[0] }
sort { $b->[1] <=> $a->[1]
||
$a->[2] cmp $b->[2]
} map { [$_, /=(\d+)/, uc($_)] } @old;
This3 ST sorts a list of files by size
@sorted_by_size =
map { $_->[0] }
sort { $a->[1] <=> $b->[1] }
map { [$_, -s] }
@files;
but with only one call to
stat(2) per file rather than the
n log n calls you'd get from this
@sorted_by_size = sort { -s $a <=> -s $b } @files;
It is important to note that using a Schwartzian
transform doesn't automatically guarantee that your
code is going to be fast or efficient. Nothing can
help you if you write code like this
map {
for my $item (@some_big_ass_list) {
do_something_expensive($_, $item);
}
} @some_big_ass_list;
In principle, any for() loop can be turned into an ST, but
sometimes amazing contortions are required. This example
should have been left as a for loop.
my $o;
map {
$o = shift;
for (@$_) {
($_->{name})=$o->fetch_name();
($_->{hist})=$o->fetch_hist();
prep_final($_); # one $_
}
finish($_); # a different $_
} map { [ $_, @{$_->fetch_list()}]} @list_of_objects;
1 Where efficiently is defined as 'with no named temps'
2 online documentation for perl 5.6.0
3 From Effective Perl Programming by Joseph Hall