Speaking of Perl, Ruby and sorting, sort in both Perl and Ruby allow you to specify a code block to implement your own arbitrary sorting routine. Perl's documentation shows you how you can define this as a subroutine and just reference the subroutine when you call sort. This is handy both for re-use and when your sort routine is complex and doesn't easily fit on one line. Ruby's sort documentation? Eh, no mention of such a thing.
In fact it is possible, but delves into a whole area of Ruby that is somewhat under-documented. The trick is that sort wants a code block, but code blocks are not first class entities. You can't name and reference a code block. However, Ruby has a couple of similar entities, Proc and lambda, that can be converted to/from code blocks and can be named and referenced. The unary ampersand operator will convert a Proc or lambda to a code block. The syntax works like this:
names = [
{:fname => 'John', :lname => 'Smith'},
{:fname => 'Jane', :lname => 'Smith'} ]
sorter = lambda do |a,b|
[a[:lname], a[:fname]] <=> [b[:lname], b[:fname]]
end
names.sort(&sorter)
Thursday, March 12, 2009
Wednesday, March 11, 2009
When sorting complex structures in Perl is is common to use syntax like:
sort { $lname{$a} <=> $lname{$b} || $fname{$a} <=> $fname{$b} } @names
The Perl sort documentation lists examples with this syntax. True to form the Ruby sort documentation doesn't show examples of anything that complex. Best I can tell anything like this doesn't work in Ruby:
a <=> b || c <=> d
Any way I write that I get back the result of the first comparison, even if the result is zero (which should trigger a fall-through to the second comparison).
Since Ruby's Array implements <=> you can achieve the desired result with:
[a, c] <=> [b, d]
sort { $lname{$a} <=> $lname{$b} || $fname{$a} <=> $fname{$b} } @names
The Perl sort documentation lists examples with this syntax. True to form the Ruby sort documentation doesn't show examples of anything that complex. Best I can tell anything like this doesn't work in Ruby:
a <=> b || c <=> d
Any way I write that I get back the result of the first comparison, even if the result is zero (which should trigger a fall-through to the second comparison).
Since Ruby's Array implements <=> you can achieve the desired result with:
[a, c] <=> [b, d]
Wednesday, March 04, 2009
A couple of MacPorts errors I just encountered:
Error: Unable to execute port: can't read "frameworks_dir": no such variable
I had version 1.6 and it seems the recommendation to fix this is to update to 1.7 (via port selfupdate). I started port in interactive mode, ran selfupdate, then tried my install again and got:
Error: Unable to open port: can't read "porturl": no such variable
I wasn't sure if it was necessary, so I ran 'sync' at this point. The install then failed with:
Error: Unable to execute port: can't read "PortInfo(name)": no such element in array
Couldn't find any info about that online, so on a lark I exited port and restarted it, after which the install proceeded.
Error: Unable to execute port: can't read "frameworks_dir": no such variable
I had version 1.6 and it seems the recommendation to fix this is to update to 1.7 (via port selfupdate). I started port in interactive mode, ran selfupdate, then tried my install again and got:
Error: Unable to open port: can't read "porturl": no such variable
I wasn't sure if it was necessary, so I ran 'sync' at this point. The install then failed with:
Error: Unable to execute port: can't read "PortInfo(name)": no such element in array
Couldn't find any info about that online, so on a lark I exited port and restarted it, after which the install proceeded.
Subscribe to:
Posts (Atom)