Workshop

The workshop provides quiz questions to help you solidify your understanding of the material covered and exercises to give you experience in using what you've learned. Try and understand the quiz and exercise answers before you go on to tomorrow's lesson.

Quiz

1:Define the differences between lists, arrays, and hashes.
A1: A list is just a collection of scalars; an array is an ordered list, indexed by position; and a hash is an unordered list of key/value pairs, indexed by the keys.
2:What do each of these variables refer to?
$foo
@foo
%foo
$foo{'key'}
$foo[$key]
$foo{$key}

A2: The answers are

$foo is a scalar variable

@foo is an array variable

%foo is a hash variable

$foo{'key'} is the value that matches 'key' in the hash %foo.

$foo[$key] is the value at the index $key in the array @foo.

$foo{$key} is the value that matches $key in the hash %foo (which might not be the same value as $foo{'key'}).

3:What are the results of the following Perl statements? Why does each expression evaluate to the result it does?
%stuff = qw(1 one 2 two 3 three 4 four);
@nums = %stuff
$foo = %stuff;
$foo = keys %stuff;

A3: The answers are
  1. The %stuff hash gets four key/value pairs: '1'/'one', '2'/'two', '3'/'three', and '4'/'four'. The qw function adds quotes around each element.

  2. @nums gets the unwound version of the key/value pairs in %stuff (key, value, key, value, and so on).

  3. $foo gets a code referring to the internal state of the hash

  4. $foo gets the number of elements (keys) in %stuff. (keys %stuff results in a list, which is evaluated in a scalar context, which then gives the number of elements in that list.)

4:What happens if you use a hash in a list context? In a scalar context?
A4: Using a hash in a list context “unwinds” the hash into its component keys and values in some internal order. In a scalar context, the hash returns two numbers indicating the internal structure of the hash.
5:How do you sort a hash?
A5: You can't sort a hash because a hash is unordered. You can, however, extract its keys or its values and then sort that resulting list.
6:Define the differences between the keys, values, and each functions.
A6: The keys function gives you a list of all the keys in the hash; the values function does the same thing with the values. The each function returns a list of a key/value pair in the hash; calling each multiple times eventually gives you all the elements in that hash.
7:What's split good for?
A7: split breaks a string up into two or more elements in a list. split is commonly used when the input you get isn't a single thing that can be assigned directly to a variable.

Exercises

1:Modify stats so that the user can enter numbers all on one line.
A1: This exercise is harder than it looks. When all the data gets entered on one line, split that line into a list. This makes some things easier and some things harder. On the one hand, you can move the processing of the data out of the while loop—it can all happen later on, after the data has been entered, rather than as the data is being entered.

On the other hand, because the data includes spaces you will run afoul of the error checking because a space is a nondigit character. The easiest way around this is to split the line inside the while loop and do the error checking on each individual element in the list.

Here's how I accomplished this script. I've included only the important parts of the stats script, from the while loop up until where the print statements start:

while () {
    print 'Enter your numbers, all on one line, separated by spaces: ';
    chomp ($input = <STDIN>);

    if ($input eq '') {
        print "Please enter some input.
";
        next;
    }

    @nums = split(' ', $input);   # split into nums

    foreach $key (@nums) {
        if ($key =~ /D/) {
            print "$key contains a non-digit character. ";
            print "Please enter your input again.
";
            @nums = ();
            next;
        }
    }

    if (@nums) { last; }
}
$count = @nums;               # get the count

foreach $num (@nums) {        # count freqs, sum
    $freq{$num} ++;
    $sum += $num;
}

@nums = sort { $a <=> $b }  @nums;
$avg = $sum / $count;
$med = $nums[$count /2];

Here's the part that starts with the while loop up until the part that prints the results:

while () {
    print 'Enter your numbers, all on one line, separated by spaces: ';
    chomp ($input = <STDIN>);

    if ($input eq '') {
        print "Please enter some input.
";
        next;
    }
    @nums = split(' ', $input);   # split into nums

    foreach $key (@nums) {
        if ($key =~ /D/) {
            print "$key contains a non-digit character.";
            print "Please enter your input again.
";
            @nums = ();
            next;
        }
    }

    if (@nums) { last; }
}

$count = @nums;               # get the count

foreach $num (@nums) {        # count freqs, sum
    $freq{$num} ++;
    $sum += $num;
}

2:Write a script that prompts you for a sentence, tells you the number of characters in the sentence, the number of words, and prints the sentence in reverse word order. (Hint: use the length, split, and reverse functions).
A2: Here's one answer:
#!/usr/local/bin/perl -w

$in = '' ; # temporary input
@sent = (); # sentence
$words = 0; # num words
@reversed = (); # reversed version

print 'Enter a sentence: ';
chomp($in = <STDIN>);
print 'Number of characters in the sentence: ';
print length $in;

@sent = split(' ', $in);
$words = @sent;
print "
Number of words in the sentence: $words
";

@reversed = reverse @sent;
print "Reversed version: 
";
print "@reversed
";

3:Modify the names.pl script to accept (and handle) names with middle names or initials (for example, Percy Bysshe Shelley or William S. Burroughs).
A3: Here's one answer:
#!/usr/local/bin/perl -w

#in = "";      # temporary input
%names = ();   # hash of names
@raw = ();     # raw words
$fn = "";      # first name
$ln = "";      # last name
while () {
    print 'Enter a name (first and last): ';
    chomp($in = <STDIN>);
    if ($in eq '') { last; }

    @raw = split(" ", $in);
    if ($#raw == 1) {  # regular case, two names
        $names{$raw[1]}  = $raw[0];
    }  else {  # build a first name from all names
        $ln = pop @raw; # remove last name
        foreach $name (@raw) { # build up first name
            $fn = $fn . ' ' . $name;
        }
        $names{$ln}  = $fn;
    }
    $fn = $ln = "";  # reset each time
}

foreach $lastname (sort keys %names) {
    print "$lastname, $names{$lastname} 
";
}

4:A hash only works with unique keys. But the names script would be more useful if it could store names with multiple duplicate last names (for example, Charlotte Bronte, Emily Bronte, and Anne Bronte). How might you modify the names.pl script to accommodate this?
A4: Here's one answer that tags each duplicate name with a unique number, and then strips those numbers off when the names are printed:
#!/usr/local/bin/perl -w

$in = '';      # temporary input
%names = ();   # hash of names
$fn = '';      # temp firstname
$ln = '';      # temp lastname
$count = 0;     # for nums

while () {
    print 'Enter a name (first and last): ';
    chomp($in = <STDIN>);
    if ($in eq '') { last; }

    ($fn, $ln) = split(' ', $in);

    if (exists $names{$ln} ) { # name is already there!
        $ln = $ln . "_" . $count; # tag this name with a number
    }

    $names{$ln}  = $fn;
    $count++;
}

foreach $lastname (sort keys %names) {
    if ($lastname =~ /_/) {  # this is a tagged name
        ($ln, undef) = split(/_/, $lastname); #remove number for printing
    }  else { $ln = $lastname }

    print "$ln, $names{$lastname} 
";
}

Another solution might be to keep the single last name as the key, and store the first names as a string, adding on the new names to the end of the string, separated by the character of your choice. Then, when printing the list, split apart all the individual first names again. There are many different ways to solve this problem.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.140.201.57