Perl vs. Python vs. Ruby
I’m evaluating Python and Ruby as replacements for Perl.I’ve been using Perl for several years and am very comfortable with it,although I’m definitely not an expert. Perl is a powerful language, butI think it’s ugly and encourages writing bad code, so I want to get ridof it. Python and Ruby both come with Mac OS X 10.2, both have BBEdit language modules, and both promise a cleaner approach to scripting. Over the past few weeks I read the Python Tutorial and the non-reference parts of Programming Ruby, however as of this afternoon I’d not written any Python or Ruby code yet.Here’s a toy problem I wanted to solve. eSellerate gives me a tab-delimited file containing information about the people who bought my shareware.I wanted a script to extract from this file the e-mail addresses ofpeople who asked to be contacted when I release the new versions of theproducts.
I decided to solve this problem in each language and then comparethe resulting programs. The algorithm I chose was just the first onethat came to mind. I coded it first in Ruby, and then ported the codeto Python and Perl, changing it as little as possible. Thus, the styleis perhaps not canonical Python or Perl, although since I’m new to Rubyit’s probably not canonical Ruby either. If I were just writing this in Perl, I might have tried to avoid Perl’s messy syntax for nested arrays and instead used an array of strings.
Here’s the basic algorithm:
[*]Read each line of standard input and break it into fields at each tab.
[*]Each field is wrapped in quotation marks, so remove them. Assume that there are no quotation marks in the interior of the field.
[*]Store the fields in an array called record.
[*]Create another array, records and fill it with all the records.
[*]Make a new array, contactRecords, that contains arrays of just the fields we care about: SKUTITLE, CONTACTME, EMAIL.
[*]Sort contactRecords by SKUTITLE.
[*]Remove the elements of contactRecords where CONTACTME is not 1.
[*]Print contactRecords to standard output, with the fields separated by tabs and the records separated by newlines.
And here’s the code:
Perl
#!/usr/bin/perl -wuse strict;my @records = ();foreach my $line ( <> ){ my @record = map {s/"//g; $_} split("\t", $line); push(@records, \@record);}my $EMAIL = 17;my $CONTACTME = 27;my $SKUTITLE = 34;my @contactRecords = ();foreach my $r ( @records ){ push(@contactRecords, [$$r[$SKUTITLE], $$r[$CONTACTME], $$r[$EMAIL]]);}@contactRecords = sort {$$a cmp $$b} @contactRecords;@contactRecords = grep($$_ eq "1", @contactRecords);foreach my $r ( @contactRecords ){ print join("\t", @$r), "\n";}The punctuation and my’s make this harder to read than it should be.
Python
#!/usr/bin/pythonimport fileinputrecords = []for line in fileinput.input(): record = records.append(record)EMAIL = 17CONTACTME = 27SKUTITLE = 34contactRecords = [, r, r] for r in records]contactRecords.sort() # default sort will group by sku titlecontactRecords = filter(lambda r: r == "1", contactRecords)for r in contactRecords: print "\t".join(r)I think the Python version is generally the cleanest to read—that is, it’s the most English-like. I had to look up how join and filter worked, because they weren’t methods of list as I had guessed.
Ruby
#!/usr/bin/rubyrecords = []while gets record = $_.split('\t').collect! {|field| field.gsub('"', '') } records << recordendEMAIL = 17CONTACTME = 27SKUTITLE = 34contactRecords = records.collect {|r| , r, r] }contactRecords.sort! # default sort will group by sku titlecontactRecords.reject! {|a| a != "1"}contactRecords.each {|r| print r.join("\t"), "\n"}This is actually the shortest version, and I think it’s the easiestto read if you aren’t put off by the block syntax. I like how thesequence of operations in the first line of the whileisn’t “backwards” as it is in the Perl and Python versions. Also, Icorrectly guessed which classes “owned” the methods and whether theywere mutators.
页:
[1]