Showing posts with label perl. Show all posts
Showing posts with label perl. Show all posts

Tuesday 6 March 2012

Perl Hash Examples

I have a friend at work who occasionally writes in Perl and so has been learning the language over quite a while, picking up new bits when he needs to write something else. I'm generally his Perl sounding-board (among other topics) and he's getting pretty good at writing things from scratch himself now, even asking questions on things I've not done with Perl, not that I'm a massively advanced Perl programmer myself.

One of the things my friend regularly needs help with and I think confuses a lot of people with Perl is with variables, and in particular hashes. People often say to me they're not sure when to use dollar, percent or at-sign in their Perl variables. I knocked together some pretty noddy code to illustrate the various ways a hash can be used in Perl code as an example for him and thought it might be useful to a wider audience so posting it here.

The source code is below with the output from running this code presented afterwards. Syntax highlighting was done courtesy of perltidy.

#!/usr/bin/perl -w
#
# Some noddy hash examples
# Note: the syntactical differences can be quite subtle
# Note: hashes don't have guaranteed ordering (run this code)

use strict;

################################################################################
# lets play with a hash
################################################################################

# define a variable as a hash with some content
my %hash = (
    'a' => 1,
    'b' => 2,
    'c' => 3
);

print "print the hash value assigned to the key 'a'\n";
print $hash{"a"}."\n\n";

print "print all of the hash values\n";
foreach my $key (keys %hash) {
  print $hash{$key}."\n";
}

print "\nprint all of the hash values in order\n";
foreach my $key (sort keys %hash) {
  print $hash{$key}."\n";
}

print "print all of the hash values with associated keys\n";
foreach my $key (keys %hash) {
  print $key . " is " . $hash{$key}."\n";
}

print "\nprint all of the hash values with associated keys in order\n";
foreach my $key (sort keys %hash) {
  print $key . " is " . $hash{$key}."\n";
}

# get rid of the hash so we're 100% sure we're not using it below!
undef %hash;


################################################################################
# lets play with a hash reference
################################################################################

# define a variable as a hash reference with some content
my $hashref = {
    'a' => 1,
    'b' => 2,
    'c' => 3
};

print "\n\nprint the hash reference value assigned to the key 'a'\n";
print $hashref->{"a"}."\n\n";

print "print all of the hash reference values\n";
foreach my $key (keys %{$hashref}) {
  print $hashref->{$key}."\n";
}

print "\nprint all of the hash reference values in order\n";
foreach my $key (sort keys %{$hashref}) {
  print $hashref->{$key}."\n";
}

print "print all of the hash reference values with associated keys\n";
foreach my $key (keys %{$hashref}) {
  print $key . " is " . $hashref->{$key}."\n";
}

print "\nprint all of the hash reference values with associated keys in order\n";
foreach my $key (sort keys %{$hashref}) {
  print $key . " is " . $hashref->{$key}."\n";
}


The output from running this code is below:

print the hash value assigned to the key 'a'
1

print all of the hash values
3
1
2

print all of the hash values in order
1
2
3
print all of the hash values with associated keys
c is 3
a is 1
b is 2

print all of the hash values with associated keys in order
a is 1
b is 2
c is 3


print the hash reference value assigned to the key 'a'
1

print all of the hash reference values
3
1
2

print all of the hash reference values in order
1
2
3
print all of the hash reference values with associated keys
c is 3
a is 1
b is 2

print all of the hash reference values with associated keys in order
a is 1
b is 2
c is 3

Tuesday 20 May 2008

Google Treasure Hunt Question 2

After solving question 1 successfully I decided to plod on and answer question 2 as well. It was, for me at least, far less challenging than the first question.

This time, you are generated a set of files with random directories and file names that you are asked to download and process. Once I got passed the immediate suspicion of downloading a zip file (for fear of viruses) it took no time at all to whip up a solution. My question was:

Here is a random zip archive for you to download:
GoogleTreasureHunt08_15866755520722619948.zip

Unzip the archive, then process the resulting files to obtain a numeric result. You'll be taking the sum of lines from files matching a certain description, and multiplying those sums together to obtain a final result. Note that files have many different extensions, like '.pdf' and '.js', but all are plain text files containing a small number of lines of text.

Sum of line 4 for all files with path or name containing BCD and ending in .pdf
Sum of line 5 for all files with path or name containing mno and ending in .rtf
Hint: If the requested line does not exist, do not increment the sum.

Multiply all the above sums together and enter the product below.
(Note: Answer must be an exact, decimal representation of the number.)


Again, my solution was Perl based and generated a correct answer of 364264342 for my particular zip file:
#!/usr/bin/perl -w
use strict;
use File::Find;
use FileHandle;
my $total1 = 0;
my $total2 = 0;
find(\&wanted, ("/home/gwhite/GoogleTreasureHunt08_15866755520722619948"));
print $total1*$total2."\n";
sub wanted {
return if (-d $File::Find::name);
if (($File::Find::name=~m!BCD!i) && ($File::Find::name=~m!\.pdf$!i)) {
my $fh = new FileHandle;
$fh->open($File::Find::name) || die ($File::Find::name." Oops: $!\n");
while (<$fh>) {
last if ($fh->input_line_number>4);
chomp($_);
$total1+=$_ if ($fh->input_line_number==4);
}
$fh->close();
}
elsif (($File::Find::name=~m!mno!i) && ($File::Find::name=~m!\.rtf$!i)) {
my $fh = new FileHandle;
$fh->open($File::Find::name) || die ($File::Find::name." Oops: $!\n");
while (<$fh>) {
last if ($fh->input_line_number>5);
chomp($_);
$total2+=$_ if ($fh->input_line_number==5);
}
$fh->close();
}
}

Monday 19 May 2008

Google Treasure Hunt

I've just discovered today (rather late I know) that Google have released a treasure hunt which is quite interesting. It's not what you might think. Given the name, I would have guessed it involved using the google search engine to find things on the Internet. However, it's actually a problem solving challenge where they pose questions and you submit your answer. I think question 2 is due out today (they obfuscate when the next question will be released), nobody seems to know how many questions there are, exactly how long this will go on for, etc. But there is a prize for "the first person to answer all the questions correctly" whatever that means.

A word of warning, don't read the rest of this if you want to work out the answer yourself!!!

My question number 1:
Google Treasure Hunt Q1
A robot is located at the top-left corner of a 65 x 61 grid (marked 'Start' in the diagram above)*.

The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the not to scale diagram below).

How many possible unique paths are there?
(Note: Answer must be an exact, decimal representation of the number.)


The problem here is the vast number of different routes that can be taken, which would overflow 32 bit computers for numbers this size. My (correct) answer was 1426507627253102510231886503468838531 which I calculated using the formula (x+y-2)! / ((x-1)! (y-1)!)

A few simple lines of Perl later and I had the answer:
#!/usr/bin/perl -w
use strict;
use Math::BigInt;
# change these to match your X & Y grid size
my $xgrid = 61;
my $ygrid = 65;
my $x = Math::BigInt->new($xgrid-1)->bfac();
my $y = Math::BigInt->new($ygrid-1)->bfac();
my $z = Math::BigInt->new($xgrid+$ygrid-2)->bfac();
print $z->bdiv($x->bmul($y))."\n";