7. Creating and accessing Hashes


1. Consider the following program that generates a hash.  

#! /usr/bin/perl
%averages = {
	'Ruth' => 350;
	'Maris' => 334;
	'Mantle' => 342;
	}
print "Printing hash outside of this string.\n", %averages, "\n";
print "Printing hash inside this string.\n %averages, \n";
$, = ":";
print "\$, is set to $, and ";
print "printing hash outside of this string.\n", %averages, "\n";

(a) What is the output of this program?
(b) If the hash values represent batting averages, change the values to be
decimalized numbers. e.g. 350 becomes .350 and rerun the program.  What
is the result?

2. Write a program that produces a hash that is defined by the
file objects in the current directory, (i.e. using ls -1).  Your script
should follow the following procedure:


3. Write a program that will take the output of the set command and
store each line in a hash keyed to the string seen to the left of the = sign.
(i.e. The Shell variable name).

4. Modify the program, written above, to accept a file containing
name=value lines. To create such a file, run set > setfile or env > envfile.
	
5. To traverse a hash in an arbitrary order, Run the following script
!# /usr/bin/perl
$info = `ls -1`;		# Get a directory listing
$infolist = split( /\n/, $info);	# Store it in an array
shift @infolist;		# Delete the 1st line

foreach $line (@infolist) {
	($owner, $size, $month) = (split( /\s+/, $line)[2,4,5];
	$usage($owner) += $size;
	$filecount($month)++;
}

print "in the usage hash:\n";
foreach $i (keys %usage) {
	print "key: $i\tvalue: $usage{$i}\n";
}

print "in the filecount hash:\n";
foreach $i (keys %filecount) {
	print "key: $i\tvalue: $filecount{$i}\n";
}

(a) How can the last two foreach loops be rewritten to eliminate the use
of the $i variable?

(b) Add the following line at the end of the program and run the update.
What is the output?
foreach (values %filecount) { print "value: $_\n"};

6. Run the following program
#! /usr/bin/perl

%planets = {
		Mercury => 58, Venus => 108, Earth => 150,
		Mars => 228, Jupiter => 778, Saturn => 1427,
		Uranus => 2870, Neptune => 4497, Pluto => 5900,
}

print "Planet\t\tDistance from Sun\n";

print "\t\t\t(Million KM)\n";

print "-"x10,"\t", "-"x17,"\n";

foreach $p (sort keys %planets) {
	$d = $ptable{$p};
	print "$p\t\t$d", "\n";
}

foreach $p (keys %planets) {
	$d = $ptable{$p};
	print "$p\t\t$d", "\n";
}

How would you produce the same output sorted by distance values rather than
by planets?

7. The current environment hash, %ENV, maintains all the environmental variables
as keys, and their values, as values.  Thus $ENV{'TERM'} represents the current
terminal type and $ENV{'PATH'} represents the search path string of directories for
the shell to find executable commands.  Write a short program that prints out 4 of
your environmental variables of your choosing.

IF IT DOESN'T WORK:

1. (b) One possible solution is:
#! /usr/bin/perl
%averages = {
	'Ruth' => '.350';
	'Maris' => '.334';
	'Mantle' => '.342';
	}
print "Printing hash outside of this string.\n", %averages, "\n";
print "Printing hash inside this string.\n %averages, \n";
$, = ":";
print "\$, is set to $, and ";
print "printing hash outside of this string.\n", %averages, "\n";

2. One possible solution is:
!# /usr/bin/perl
$info = `ls -1`;		# Get a directory listing
$infolist = split( /\n/, $info);	# Store it in an array
shift @infolist;		# Delete the 1st line

foreach $line (@infolist) {
	@attributes = split( /\s+/, $line);
	$perms = $attributes[0];
	$owner = $attributes[2];
	$size = $attributes[4];
	$name = $details[8];
	
#  or instead use:
# ($perms, $pwner, $size, $name) = @attributes[0,2,4,8];
#
# or better:
# ($perms, $pwner, $size, $name) = 
#			split(/\s+/. $line);

$usage{$owner} += $size;
$filecount{$owner}++;
$access{$name} = $perms;

}
$, = "...";

print "Usage Hash: ", %usage, "\n";
print "Filecount Hash: ", %filecount, "\n";
print "Access Hash: ", %access, "\n";

3. One solution to question 3 is:
#! /usr/bin/perl
$data = `set`;

@lines = split (/\n/, $data);

foreach $line (@lines) {
	($key, $val) = split (/=/, $line);
	$env{$key} = $val;
}

$, = "\t";
print %env, "\n";

4. One solution to question 4 is:
#! /usr/bin/perl
open (IN, $ARGV[0]) or die "Couldn't open file [$ARGV[0]]";

while ($nextline = <IN>) {
	chomp $nextline;

	($key, $val) = split (/=/, $nextline);
	$env{$key} = $val;
}

$, = ":";
print %env, "\n";
close (IN);

5. In Question 5(a), Use the default variable $_ as in:
	foreach (keys %filecount) { print "key: $_\tvalue: $filecount{$_}\n"};
	
	In Question 5(b), The values of the hash are printed as if they are in
	an array with an arbitrary order.

6. In Question 6, one solution is:
#! /usr/bin/perl

%planets = {
		Mercury => 58, Venus => 108, Earth => 150,
		Mars => 228, Jupiter => 778, Saturn => 1427,
		Uranus => 2870, Neptune => 4497, Pluto => 5900,
}

print "Planet\t\tDistance from Sun\n";

print "\t\t\t(Million KM)\n";

print "-"x10,"\t", "-"x17,"\n";

while ( ($k, $v) = each %planets ) {
	$ values{$v} = $k;
}

foreach $d ( sort {$a <=> $b} keys %values) {
	$p = $values{$d};
	print "$p\t\t$d", "\n";
}

7. One solution to Question 7 is:
	#! /usr/bin/perl
	print "Environmental Variable \$TERM is $ENV{'TERM'}\n";
	print "Environmental Variable \$HOME is $ENV{'HOME'}\n";
	print "Environmental Variable \$PATH is $ENV{'PATH'}\n";
	print "Environmental Variable \$SHELL is $ENV{'SHELL'}\n";

Questions about the questions? Send mail to Robert Katz: rkatz@ned.highline.ctc.edu
Last Update February 2, 2002