After my last post about perl sorting, a friend of mine, who is an ardent hater of Perl (amongst a long list of other things), pointed out that his shell script was not only shorter, but also faster at sorting out the sendmail virtusertable. Whilst he was right about the speed I thought it lacked elegance and flexibility. So, as my next volley across the bows, this sort program sorts a list of names based upon the ‘value’ of the name ( a=1, b=2, etc). I’ve used a few other bits in here not previously ‘blogged’ so i’ll explain how it works, stage by stage. The script follows:
#! /usr/bin/perl -w use strict; my %letter_vals; my $counter = 1; # function to calculate the 'value' of the name sub get_value{ my $data = shift; my $running_total; my @letters = split(//, $data); for (@letters){ $running_total += $letter_vals{$_}; } return $running_total; } # load up the 'lookuphash' for ("a" .. "z"){ $letter_vals{$_} = $counter; $counter ++; } # define the initail list of names my @unsorted= qw /aitch babs dan cath nads japes max/; # sort based on the name 'value' my @sorted = sort {&get_value($a) <=> &get_value($b)} @unsorted; # add the score next to the name @sorted = map {$_, "(" . &get_value($_) .")"} @sorted; # proudy display the results print "\nResult: @sorted\n";
When run the output is:
Result: dan (19) babs (24) cath (32) nads (38) max (38) aitch (41) japes (51)
From the top, the ‘sub’ takes the scalar value submitted and breaks it into an array of letters using the split function note the ‘//’. Then it rattles through the array adding the value of each letter to the running total and finally returning the total.
I build a hash to do easy lookups so $hash{“a”} = 1, $hash{“b”} = 2 , etc. I could have done this within the function but chose to do it ‘globally’ so the hash is only built once.
The sort function differs from the last entry as we now need a numeric sort so ‘cmp’ becomes ‘<=>’ .
I used the map function to add the score for each name in brackets for the output.