Yeah, but your scientists were so preoccupied with whether or not they could, they didn't stop to think if they should. Dr. Ian Malcolm
I have recently come to a knowledge of the power of
map
and grep
when dealing with hashes and arrays of data. The key to entering this mindset is the Schwartzian Transform. Here is a canonical example.
@sorted = map { $_->[0] } sort { $a->[1] cmp $b->[1] } map { [$_, foo($_)] } @unsorted;For years, I looked at that and said "Huh?", then wrote
for my $i ( @unsorted ) { ... }
or something like that. In fact, let's look at a for-loop implementation that would get similar results.my @sorted ; for my $i ( @unsorted ) { my $j = foo($i) ; $hash{$j} = $i ; } for my $k ( sort { $a cmp $b } keys %hash ) { push @sorted , $hash{ $k } ; }
That's a lot more code, and it would not surprise me at all if my code was far slower than the Wikipedia example code, but I understood for loops from my first year of programming, so I can look at the second example and immediately understand it, and would still understand it if I came back and looked at it in a month.
Of course, you can comment this sort of thing to explain it to your later self.
@sorted = map { $_->[0] } # taking away the sorting field sort { $a->[1] cmp $b->[1] } #sorting by the 2nd field in the anonymous arrays map { [$_, foo($_)] } # an array of 2-element anonymous arrays @unsorted; # the original unsorted array
I find myself using the
map
and grep
method a lot lately. It avoids a lot of extra arrays floating around, but as I looked at the Schwartzian Transform and boggled for years, I could see myself, or the next person holding this seat, looking at the code for hours and failing to get it. But at least, now that I can code like that, I can wonder if I should...
""I could see myself, or the next person holding this seat, looking at the code for hours and failing to get it. But at least, now that I can code like that, I can wonder if I should...""
ReplyDeleteYou definitely can, and should. :)
The more you use Perl, the more comfortable you will be with map, grep, and sort.
You will look at a long chain of them and immediately understand what they're doing, and why they're doing it.
To an experienced Perl developer, they're actually a lot EASIER to read than a bunch of 'for' loops. So keep at it, and it will be second nature.
The value of the Schwartzian Transform is that it encapsulates a complex concept in a simple meme.
ReplyDeleteThe underlying concept is "efficiently sort a list by a calculated value".
Calling that a "Schwartzian Transform" and implementing it in a consistent way increases the abstraction level of your code.
Of course, this is really a hackaround for an insufficiently power language. What we really want is for the Perl interpreter to recognize what we're doing and implement the caching for us.
The best explanation of the Schwartzian Transform is from Joseph Hall. It's in either edition of Effective Perl Programming. It's the excellent writing that allows people to finally grok it.
ReplyDeleteI agree with brian. After reading _Effective Perl Programming_ I was able to grok what the Schwartzian Transform was doing...and then extend that idiom to other list/array based operations.
ReplyDeleteOfcourse, in this specific case rather than manually writing the Schwartzian yourself, you could just:
ReplyDeleteuse List::UtilsBy 'sort_by';
@sorted = sort_by { foo($_) } @unsorted;