Difference between revisions of "Perl programming exercises 2"

From "A B C"
Jump to navigation Jump to search
 
(9 intermediate revisions by the same user not shown)
Line 5: Line 5:
  
  
{{fix}}
+
Small programming exercises for an introduction to Perl.
 
 
 
 
Summary ...
 
 
 
  
 
__TOC__
 
__TOC__
Line 16: Line 12:
  
 
 
 
 
==Contents==
 
 
  
 
;Basic Perl Programming - Programming exercises
 
;Basic Perl Programming - Programming exercises
 
<small>Boris Steipe acknowledges contributions by Jennifer Tsai, Sanja Rogic and Sohrab Shah.</small>
 
<small>Boris Steipe acknowledges contributions by Jennifer Tsai, Sanja Rogic and Sohrab Shah.</small>
  
This page contains programming exercises designed to help you try your hand at translating a concept into a working program.
+
Here are programming exercises that focus on translating a concept into a working script.
  
[[Perl_programming_1| The preceding section]] covers a section I have called syntax examples ... they are simple tasks that ask you to write functioning code syntactically correct.  
+
[[Perl_programming_exercises_1| The preceding section]] covers a section I have called syntax examples ... they are simple tasks that ask you to write functioning code syntactically correct.  
  
The first section describes tasks, for you to work through. In the second section, I have given some additional hints - which functions you might use or which strategy to solve the problem. Finally - for desperate cases when you really can't get your code to work - I have included sample solutions. Should you really need to look up the solutions, study the example, put it away and make it a point to write your program from scratch, with different code and perhaps some variation in function. If you merely copy code you will not profit from the exercises.
 
  
Don't be satisfied until you understand what you are doing.
+
For each task you will find
 +
# a description of the task your code should achieve;
 +
# some hints how to go about solving it - which functions you might use or which strategy; and
 +
# sample code for reference if you are stuck. Should you really need to look up the samples, carefully study the code, put it away and then write your own script from scratch, with different code and perhaps some variation in function. If you merely copy code, or read it with mild interest and move on, you will probably be wasting your time.
  
 +
;Don't be satisfied until you understand what you are doing.
  
  
==Programming Exercises: Tasks==
 
  
====1. Hello World====
+
==Tasks==
;Executable program
 
Write a Perl program helloWorld.pl that prints out "Hello World" (or anything else of your liking) to the terminal. Make your program executable (chmod u+x helloWorld.pl) so that you don't need to invoke the Perl interpreter explicitly from the command line (i.e. just "$ helloWorld.pl" and not
 
"$ perl helloWorld.pl").
 
  
 +
===Hello World===
  
====2. cat====
 
;Keyboard input
 
Write a Perl program cat.pl that prints to the terminal a single line that you type at the keyboard.
 
  
 +
&nbsp;
 +
;Executable program
 +
Write a Perl program <code>helloWorld.pl</code> that prints out "Hello World" (or whatever you fancy) to the terminal. Make your program executable (<code>chmod u+x helloWorld.pl</code>) so that you don't need to invoke the Perl interpreter explicitly from the command line (i.e. just "<code>$ ./helloWorld.pl</code>" should run it, you shouldn't need to type "<code>$ perl helloWorld.pl</code>").
  
====3. lc====
+
&nbsp;
;More keyboard input
+
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#EEEEFF; padding:10px;">
Write a Perl program lc.pl that reads one or many lines from STDIN, converts them to lowercase and prints them to the terminal. Use this interactively, typing input (end by typing <ctrl>D), then use this by redirecting a textfile to your program, then "pipe" the output of the Unix "ls" command into your program.
+
Hints:
 +
<div class="mw-collapsible-content">
  
  
====4. max====
+
&nbsp;
;Condition
+
Simply use the print(); function.
Write a Perl program max.pl that prompts for and reads two numbers from STDIN, and outputs the larger of the two numbers to the terminal. Remember to consider the case that the numbers may be equal.
 
  
  
====5.max (with subroutine)====
+
&nbsp;
;Subroutine
+
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#DDDDFF; padding:10px;">
Rewrite max.pl so the comparison is done in a subroutine: pass the two numbers as arguments into a subroutine and return the larger of the two. Such a program may be a useful framework for comparing two datasets with a non-trivial metric. Instead of simply picking the larger value, the subroutine could compare according to some sophisticated algortithm
+
Code:
 +
<div class="mw-collapsible-content">
  
  
====6. anagram====
+
&nbsp;
;Array
+
<source lang="perl">
Write a Perl program anagram.pl that reads a string from STDIN and returns ten random permutations of this string. This will require a number of concepts and techniques of working with arrays - defining an array, assigning values to an array, or to individual fields of an array, using a variable as an index to an array in order to read from or write to specific fields, and more. First split your string into individual elements of an array. Use a subroutine that randomizes this array by looping over every position of the array, and swapping the contents of this position with a randomly chosen other position of the array, except itself. Write this in pseudocode first. The Perl functions you will need are split(); and rand();.
+
#!/usr/bin/perl
 +
use warnings;
 +
use strict;
  
 +
print("Hello World !\n");
  
====7.anastring ====
+
exit();
;Substring calisthenics
+
</source>
Copy anagram.pl to a file named anastring.pl and use the Perl strlen(); and substr(); functions to permute the string (in place !) instead of shuffling fields of an array. Make a point of programming this incrementally step by step, writing output as you go along to make sure you are doing it right. Of course you could also shuffle using the split() and join() functions on a string ... but that would not be "in place".
 
  
  
====8. anastring (with commandline input)====
+
&nbsp;
;Commandline arguments
+
</div>
Modify anastring.pl so you can pass the number of permutations to the program in the commandline ( via @ARGV ), make sure that the default is 1, if no argument is given. This tool could be part of a routine to generate random data to test statistical significance.
+
</div>
 +
</div>
 +
</div>
  
  
====9. sort====
+
&nbsp;
;Sorting
+
===cat()===
Write a Perl program sort.pl that takes in strings (e.g. names) from STDIN, stores them in an array, sorts them in alphabetical order, using the Perl sort(); function and prints them out to the terminal.
 
  
  
====10. fastaParser====
 
;Hash (associative array)
 
Write a Perl program fastaParser.pl that takes in a FASTA file of any protein as input and outputs it as three-letter amino acid code separated by spaces to the terminal. Use a hash to store the mapping between the one-letter amino acid code and the three-letter amino acid code.
 
  
 +
&nbsp;
 +
;Keyboard input
 +
Write a Perl program cat.pl that prints to the terminal a single line that you type at the keyboard.
  
====11. factorial====
+
&nbsp;
;Iteration and recursion
+
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#EEEEFF; padding:10px;">
Write a Perl program factorial.pl that takes in a number as input and calculates the factorial of that number. Note that this can be done in (at least) two ways: the first way  is to use a <code>for</code> loop in the body of the program...
+
Hints:
 +
<div class="mw-collapsible-content">
  
  
====12. factorial(recursive)====
+
&nbsp;
(OPTIONAL) ...the second way is to use a subroutine recursively to yield the factorial of a number. Try programming it this way as well.
 
 
 
==Programming Exercises: Hints==
 
 
 
====1. Hello World====
 
Simply use the print(); function.
 
 
 
 
 
====2. cat====
 
 
Use the diamond operator to read from STDIN, assign this to a variable, then print the contents of the variable. Just one statement, no loop is required.
 
Use the diamond operator to read from STDIN, assign this to a variable, then print the contents of the variable. Just one statement, no loop is required.
  
 +
&nbsp;
 +
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#DDDDFF; padding:10px;">
 +
Code:
 +
<div class="mw-collapsible-content">
  
====3. lc====
 
Use a while loop to test the successful assignment of <STDIN> to a variable as its loop condition. This way thee loop runs until STDIN reads EOF (End of File). Use the perl lc(); function to change case. Assign the return value to a variable and print it.
 
  
 
+
&nbsp;
====4. max====
 
You need an
 
 
<source lang="perl">
 
<source lang="perl">
if (condition) { do ... }
+
#!/usr/bin/perl
</source>
+
use warnings;
construction to print one or the other numbers, depending on the result of the comparison. Remember the difference between numeric and alphanumeric comparisons! You have to chomp(); your input variables, to be able to compare them as numbers.
+
use strict;
  
 +
my $line;
  
====5. max (with subroutine)====
+
$line = <STDIN>;
Remember that Perl uses the default array "@_" to pass values into subroutines. You need to assign the contents of @_ to variables (or other arrays) in order to be able to use the values. The easiest way to do this, is to assign the array to values in a list - e.g.
 
  
<source lang="perl">
+
print( $line, "\n");
my ($a) = @_; or ...
 
my ($a, $b) = @_;
 
</source>
 
  
'''Note that the following will not work as expected !'''
+
exit();
 
 
<source lang="perl">
 
my $a = @_;
 
 
</source>
 
</source>
  
If you would do this, you would be assigning an array "@" to a scalar "$". The problem is that this is legal, the compiler does not complain or warn, but this does not assign the first value in the array, it assigns the integer value of the number of fields the array uses ! This is a fine case of a statement being syntactically correct but logically wrong. If in doubt whether you are doing the right thing, always print your values from within the subroutine, as a development test, to make sure they are what you expect them to be.
 
  
<!--
+
&nbsp;
// note to self: write examples explicitly!
+
</div>
 +
</div>
 +
</div>
 +
</div>
  
You can return single scalars from subroutines, or you can return multiple values, as lists,  as in the following example:
 
  
subroutine returns... main program assigns ...
+
&nbsp;
 +
===lc()===
  
<source lang="perl">
 
return($a);
 
my $larger = max($in1, $in2);
 
  
  
return($a, $b);
+
&nbsp;
+
;More keyboard input
my ($larger, $smaller) = max($in1, $in2);
+
Write a Perl program lc.pl that reads one or many lines from STDIN, converts them to lowercase and prints them to the terminal. Use this interactively, typing input (end by typing <ctrl>D), then use this by redirecting a textfile to your program, then "pipe" the output of the Unix "ls" command into your program.
</source>
 
  
 +
&nbsp;
 +
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#EEEEFF; padding:10px;">
 +
Hints:
 +
<div class="mw-collapsible-content">
  
-->
 
  
====6. anagram====
+
&nbsp;
You have to chomp(); your input in order not to shuffle the newline character (“return” character) into your randomized strings; otherwise you’ll end up with strangely shortened versions of your randomized string, split into two parts. To get the array size, use the index of the last array position plus one (remember that array positions are numbered starting at 0, not 1 ! ). To split a string into individual elements of an array, use split(//, $input); with no delimiter, i.e. with no other characters in between the slashes, not even a space. Assigning the result of split(); to an array puts every character of the string into its own array field. When randomizing the array, note that rand(); returns a random rational number, not an integer, so you may need to use int(); to truncate the result of rand(); and just return the integer part. Use variables to store values from the array before the swap, otherwise the original value stored in a given array position will be lost before it can be copied over to the new array position that you want to swap it to. Also note that all array positions should be switched, so you need to consider the case that your random integer is the same as the position of the original value.
+
Use a while loop to test the successful assignment of <STDIN> to a variable as its loop condition. This way thee loop runs until STDIN reads EOF (End of File). Use the perl lc(); function to change case. Assign the return value to a variable and print it.
  
When you are done, see what happens when you comment out the chomp(); function, for effect.
+
&nbsp;
 +
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#DDDDFF; padding:10px;">
 +
Code:
 +
<div class="mw-collapsible-content">
  
  
====7. anastring====
+
&nbsp;
This is similar to anagram.pl but uses substr(); on the original string instead of shuffling fields of an array. Remember that substr(); can be used to extract defined substrings as well as to replace them. As with anagram.pl, use variables to store the characters that you want to swap, to prevent the original character from being lost when you overwrite one of the two positions in the string. Use int(); on the result of rand(); to get a random position in the string and think carefully about the range of numbers that this should produce. The range is obviously a function of the string-length - but does it start at 0 or 1 and does it extend to the length itself, or more or less ? Test whether the range you produce is correct.
+
<source lang="perl">
 +
#!/usr/bin/perl
 +
use warnings;
 +
use strict;
  
 +
while (my $line = <STDIN>) {
 +
    $line = lc($line);
 +
    print( $line, "\n");
 +
}
 +
exit();
 +
</source>
  
====8. anastring with commandline input====
 
The whole commandline that you give to a Perl program is stored in the array-variable named @ARGV. $ARGV[0] is the first argument  $ARGV[0] is the second, and so on. To check whether some variable is defined, use the function defined($someVariable); in an if statement. If no command line argument has been typed, $ARGV[0] will be undefined.
 
  
 +
&nbsp;
 +
</div>
 +
</div>
 +
</div>
 +
</div>
  
====9. sort====
 
Declare a variable to use as an array index and initialize it with the value 0. Assign the entire input string to the current array position $array[$index], then increment the index variable so it points to the next available field. (The field of an array can hold integers, floats, strings, other arrays, hashes, references to arrays, ...) Sort the array using the Perl sort(); function.
 
  
 +
&nbsp;
 +
===max===
  
====10. fastaParser====
 
To parse out the definition line of a FASTA file, use substr(); to get the first character of each line and test to see if it is ">". Read in each line of the FASTA file and store it as an array, character by character (as with anagram.pl). Loop over the contents of the array and retrieve the three-letter code for the amino acid, using a hash that maps one-letter amino acid codes to three-letter amino acid codes.
 
  
Hint about the hash: it’s similar in concept to the amino acid code hash that was used in one of the programs written in class… think about which way the amino acid code mapping was applied with that hash and try to apply the principles here.
 
  
 +
&nbsp;
 +
;Condition
 +
Write a Perl program max.pl that prompts for and reads two numbers from STDIN, and outputs the larger of the two numbers to the terminal. Remember to consider the case that the numbers may be equal.
  
====11. factorial====
+
&nbsp;
Remember to think about all types of outcomes when designing your conditions in if/else statements: a negative factorial is undefined, and both 0! and 1! are equal to 1. Use die(); rather than exit(); to indicate that an unexpected input has been entered that the program cannot handle. Both cause the program to terminate, but die(); allows you to enter an error message on program exit, e.g. die(“Negative factorial is undefined.”);. Use a for loop to multiply out the factorial of the input number, and use a variable to store the value of the factorial during intermediate steps in calculation.
+
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#EEEEFF; padding:10px;">
 +
Hints:
 +
<div class="mw-collapsible-content">
  
  
====12. factRecurse====
+
&nbsp;
Recursion is when a subroutine or program calls itself. Such a subroutine or program needs defined “base cases”, for which the subroutine can return a value without having to call itself again (allowing the program or subroutine to terminate). The base cases for factRecurse are exactly the same as for factorial.pl – negative factorial should return an error, and both 0! and 1! should return 1. In place of the for loop used in factorial.pl, each recursion of the subroutine in factRecurse.pl performs one small step (the small step that would be performed with each iteration of the for loop) and then applies it to the next subroutine call.
+
You need an
(e.g. $resultOfSomeStep + subRoutine($currentCall – 1)).
+
<source lang="perl">
 +
if (condition) { do ... }
 +
</source>
 +
construction to print one or the other numbers, depending on the result of the comparison. Remember the difference between numeric and alphanumeric comparisons! You have to chomp(); your input variables, to be able to compare them as numbers.
  
 +
&nbsp;
 +
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#DDDDFF; padding:10px;">
 +
Code:
 +
<div class="mw-collapsible-content">
  
 
==Programming Exercises:  Sample Solutions==
 
 
 
====1. Hello World====
 
  
 +
&nbsp;
 
<source lang="perl">
 
<source lang="perl">
 
#!/usr/bin/perl
 
#!/usr/bin/perl
Line 195: Line 200:
 
use strict;
 
use strict;
  
print("Hello World !\n");
+
print("Enter a number: ");            # User inputs
 +
my $input1 = <STDIN>;
  
exit();
+
print("Enter a second number: ");
</source>
+
my $input2 = <STDIN>;
  
 +
chomp($input1);                      # Chomp off trailing newline characters
 +
chomp($input2);
  
 +
if ($input1 > $input2) {
 +
  print("$input1 is larger than $input2.\n");
 +
} elsif ($input1 == $input2) {
 +
  print ("$input1 and $input2 are equal.\n");
 +
} else {
 +
  print ("$input2 is larger than $input1.\n");
 +
}
  
 +
exit();
 +
</source>
  
====2. cat====
 
  
<source lang="perl">
+
&nbsp;
#!/usr/bin/perl
+
</div>
use warnings;
+
</div>
use strict;
+
</div>
 +
</div>
  
my $line;
 
  
$line = <STDIN>;
+
&nbsp;
 +
===max (with subroutine)===
  
print( $line, "\n");
 
  
exit();
 
</source>
 
  
 +
&nbsp;
 +
;Subroutine
 +
Rewrite max.pl so the comparison is done in a subroutine: pass the two numbers as arguments into a subroutine and return the larger of the two. Such a program may be a useful framework for comparing two datasets with a non-trivial metric. Instead of simply picking the larger value, the subroutine could compare according to some sophisticated algortithm
  
 +
&nbsp;
 +
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#EEEEFF; padding:10px;">
 +
Hints:
 +
<div class="mw-collapsible-content">
  
  
====3. lc====
+
&nbsp;
 +
Remember that Perl uses the default array "@_" to pass values into subroutines. You need to assign the contents of @_ to variables (or other arrays) in order to be able to use the values. The easiest way to do this, is to assign the array to values in a list - e.g.
  
 
<source lang="perl">
 
<source lang="perl">
#!/usr/bin/perl
+
my ($a) = @_; or ...
use warnings;
+
my ($a, $b) = @_;
use strict;
 
 
 
while (my $line = <STDIN>) {
 
    $line = lc($line);
 
    print( $line, "\n");
 
}
 
exit();
 
 
</source>
 
</source>
  
 +
'''Note that the following will not work as expected !'''
  
 +
<source lang="perl">
 +
my $a = @_;
 +
</source>
  
====4. max.pl (plain version)====
+
If you would do this, you would be assigning an array "@" to a scalar "$". The problem is that this is legal, the compiler does not complain or warn, but this does not assign the first value in the array, it assigns the integer value of the number of fields the array uses ! This is a fine case of a statement being syntactically correct but logically wrong. If in doubt whether you are doing the right thing, always print your values from within the subroutine, as a development test, to make sure they are what you expect them to be.
  
<source lang="perl">
+
<!--
#!/usr/bin/perl
+
// note to self: write examples explicitly!
use warnings;
 
use strict;
 
  
print("Enter a number: ");            # User inputs
+
You can return single scalars from subroutines, or you can return multiple values, as lists,  as in the following example:
my $input1 = <STDIN>;
 
  
print("Enter a second number: ");
+
subroutine returns... main program assigns ...
my $input2 = <STDIN>;
 
  
chomp($input1);                       # Chomp off trailing newline characters
+
<source lang="perl">
chomp($input2);
+
return($a);
 +
my $larger = max($in1, $in2);
  
if ($input1 > $input2) {
 
  print("$input1 is larger than $input2.\n");
 
} elsif ($input1 == $input2) {
 
  print ("$input1 and $input2 are equal.\n");
 
} else {
 
  print ("$input2 is larger than $input1.\n");
 
}
 
  
exit();
+
return($a, $b);
 +
 +
my ($larger, $smaller) = max($in1, $in2);
 
</source>
 
</source>
  
  
 +
-->
 +
 +
&nbsp;
 +
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#DDDDFF; padding:10px;">
 +
Code:
 +
<div class="mw-collapsible-content">
  
====5. max.pl (subroutine version)====
 
  
 +
&nbsp;
 
<source lang="perl">
 
<source lang="perl">
 
#!/usr/bin/perl
 
#!/usr/bin/perl
Line 310: Line 327:
  
  
 +
&nbsp;
 +
</div>
 +
</div>
 +
</div>
 +
</div>
 +
 +
 +
&nbsp;
 +
===anagram===
  
  
====6. anagram.pl====
 
  
 +
&nbsp;
 +
;Array
 +
Write a Perl program anagram.pl that reads a string from STDIN and returns ten random permutations of this string. This will require a number of concepts and techniques of working with arrays - defining an array, assigning values to an array, or to individual fields of an array, using a variable as an index to an array in order to read from or write to specific fields, and more. First split your string into individual elements of an array. Use a subroutine that randomizes this array by looping over every position of the array, and swapping the contents of this position with a randomly chosen other position of the array, except itself. Write this in pseudocode first. The Perl functions you will need are split(); and rand();.
 +
 +
&nbsp;
 +
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#EEEEFF; padding:10px;">
 +
Hints:
 +
<div class="mw-collapsible-content">
 +
 +
 +
&nbsp;
 +
You have to chomp(); your input in order not to shuffle the newline character (“return” character) into your randomized strings; otherwise you’ll end up with strangely shortened versions of your randomized string, split into two parts. To get the array size, use the index of the last array position plus one (remember that array positions are numbered starting at 0, not 1 ! ). To split a string into individual elements of an array, use split(//, $input); with no delimiter, i.e. with no other characters in between the slashes, not even a space. Assigning the result of split(); to an array puts every character of the string into its own array field. When randomizing the array, note that rand(); returns a random rational number, not an integer, so you may need to use int(); to truncate the result of rand(); and just return the integer part. Use variables to store values from the array before the swap, otherwise the original value stored in a given array position will be lost before it can be copied over to the new array position that you want to swap it to. Also note that all array positions should be switched, so you need to consider the case that your random integer is the same as the position of the original value.
 +
 +
When you are done, see what happens when you comment out the chomp(); function, for effect.
 +
 +
&nbsp;
 +
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#DDDDFF; padding:10px;">
 +
Code:
 +
<div class="mw-collapsible-content">
 +
 +
 +
&nbsp;
 
<source lang="perl">
 
<source lang="perl">
 
#!/usr/bin/perl
 
#!/usr/bin/perl
Line 344: Line 391:
  
 
exit();
 
exit();
 
  
 
# ===== randomize () =============================
 
# ===== randomize () =============================
Line 405: Line 451:
 
deserves some comment. $j starts as the index of the last element in the array. $rand(n) returns a random, rational number from the interval [0,n[  i.e.  0 ≤ number < n. Assume our array had four elements: $rand(3+1) would return numbers from 0.000... to 3.999... Since int() does not round the number, but just truncates its decimals and returns its integer part, we return random integers from 0 to 3, each with uniform probability. That happens to be exactly the range of elements that can be used to randomly point somewhere into our array.
 
deserves some comment. $j starts as the index of the last element in the array. $rand(n) returns a random, rational number from the interval [0,n[  i.e.  0 ≤ number < n. Assume our array had four elements: $rand(3+1) would return numbers from 0.000... to 3.999... Since int() does not round the number, but just truncates its decimals and returns its integer part, we return random integers from 0 to 3, each with uniform probability. That happens to be exactly the range of elements that can be used to randomly point somewhere into our array.
  
====7. anastring====
+
&nbsp;
 +
</div>
 +
</div>
 +
</div>
 +
</div>
 +
 
  
 +
&nbsp;
 +
===anastring ===
 +
 +
 +
 +
&nbsp;
 +
;Substring calisthenics
 +
Copy anagram.pl to a file named anastring.pl and use the Perl strlen(); and substr(); functions to permute the string (in place !) instead of shuffling fields of an array. Make a point of programming this incrementally step by step, writing output as you go along to make sure you are doing it right. Of course you could also shuffle using the split() and join() functions on a string ... but that would not be "in place".
 +
 +
&nbsp;
 +
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#EEEEFF; padding:10px;">
 +
Hints:
 +
<div class="mw-collapsible-content">
 +
 +
 +
&nbsp;
 +
This is similar to anagram.pl but uses substr(); on the original string instead of shuffling fields of an array. Remember that substr(); can be used to extract defined substrings as well as to replace them. As with anagram.pl, use variables to store the characters that you want to swap, to prevent the original character from being lost when you overwrite one of the two positions in the string. Use int(); on the result of rand(); to get a random position in the string and think carefully about the range of numbers that this should produce. The range is obviously a function of the string-length - but does it start at 0 or 1 and does it extend to the length itself, or more or less ? Test whether the range you produce is correct.
 +
 +
&nbsp;
 +
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#DDDDFF; padding:10px;">
 +
Code:
 +
<div class="mw-collapsible-content">
 +
 +
 +
&nbsp;
 
<source lang="perl">
 
<source lang="perl">
 
#!/usr/bin/perl
 
#!/usr/bin/perl
Line 439: Line 515:
  
  
 +
&nbsp;
 +
</div>
 +
</div>
 +
</div>
 +
</div>
 +
 +
 +
&nbsp;
 +
===anastring (with commandline input)===
 +
 +
 +
 +
&nbsp;
 +
;Commandline arguments
 +
Modify anastring.pl so you can pass the number of permutations to the program in the commandline ( via @ARGV ), make sure that the default is 1, if no argument is given. This tool could be part of a routine to generate random data to test statistical significance.
 +
 +
&nbsp;
 +
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#EEEEFF; padding:10px;">
 +
Hints:
 +
<div class="mw-collapsible-content">
 +
 +
 +
&nbsp;
 +
The whole commandline that you give to a Perl program is stored in the array-variable named @ARGV. $ARGV[0] is the first argument  $ARGV[0] is the second, and so on. To check whether some variable is defined, use the function defined($someVariable); in an if statement. If no command line argument has been typed, $ARGV[0] will be undefined.
 +
 +
 +
&nbsp;
 +
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#DDDDFF; padding:10px;">
 +
Code:
 +
<div class="mw-collapsible-content">
  
====8. anastring, with commandline argument====
 
  
 +
&nbsp;
 
Simply change:
 
Simply change:
  
Line 465: Line 571:
  
  
====9. sort.pl====
+
&nbsp;
 +
</div>
 +
</div>
 +
</div>
 +
</div>
 +
 
 +
 
 +
&nbsp;
 +
 
 +
===sort===
 +
 
 +
 
 +
 
 +
&nbsp;
 +
;Sorting
 +
Write a Perl program sort.pl that takes in strings (e.g. names) from STDIN, stores them in an array, sorts them in alphabetical order, using the Perl sort(); function and prints them out to the terminal.
 +
 
 +
&nbsp;
 +
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#EEEEFF; padding:10px;">
 +
Hints:
 +
<div class="mw-collapsible-content">
 +
 
 +
 
 +
&nbsp;
 +
Declare a variable to use as an array index and initialize it with the value 0. Assign the entire input string to the current array position $array[$index], then increment the index variable so it points to the next available field. (The field of an array can hold integers, floats, strings, other arrays, hashes, references to arrays, ...) Sort the array using the Perl sort(); function.
 +
 
 +
&nbsp;
 +
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#DDDDFF; padding:10px;">
 +
Code:
 +
<div class="mw-collapsible-content">
 +
 
  
 +
&nbsp;
 
<source lang="perl">
 
<source lang="perl">
 
#!/usr/bin/perl
 
#!/usr/bin/perl
Line 491: Line 628:
 
</source>
 
</source>
  
 +
 +
 +
&nbsp;
 +
</div>
 +
</div>
 +
</div>
 +
</div>
 +
 +
 +
&nbsp;
 +
===fastaParser===
  
  
  
====10. fastaParser.pl====
+
&nbsp;
 +
;Hash (associative array)
 +
Write a Perl program fastaParser.pl that takes in a FASTA file of any protein as input and outputs it as three-letter amino acid code separated by spaces to the terminal. Use a hash to store the mapping between the one-letter amino acid code and the three-letter amino acid code.
  
 +
&nbsp;
 +
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#EEEEFF; padding:10px;">
 +
Hints:
 +
<div class="mw-collapsible-content">
  
 +
 +
&nbsp;
 +
To parse out the definition line of a FASTA file, use substr(); to get the first character of each line and test to see if it is ">". Read in each line of the FASTA file and store it as an array, character by character (as with anagram.pl). Loop over the contents of the array and retrieve the three-letter code for the amino acid, using a hash that maps one-letter amino acid codes to three-letter amino acid codes.
 +
 +
Hint about the hash: it’s similar in concept to the amino acid code hash that was used in one of the programs written in class… think about which way the amino acid code mapping was applied with that hash and try to apply the principles here.
 +
 +
 +
&nbsp;
 +
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#DDDDFF; padding:10px;">
 +
Code:
 +
<div class="mw-collapsible-content">
 +
 +
 +
&nbsp;
 
<source lang="perl">
 
<source lang="perl">
 
#!/usr/bin/perl
 
#!/usr/bin/perl
Line 566: Line 734:
  
 
}  # end sub
 
}  # end sub
<source lang="perl">
+
</source>
 +
 
 +
 
 +
&nbsp;
 +
</div>
 +
</div>
 +
</div>
 +
</div>
 +
 
 +
 
 +
&nbsp;
 +
===factorial===
 +
 
 +
 
 +
 
 +
&nbsp;
 +
;Iteration and recursion
 +
Write a Perl program factorial.pl that takes in a number as input and calculates the factorial of that number. Note that this can be done in (at least) two ways: the first way  is to use a <code>for</code> loop in the body of the program...
  
 +
&nbsp;
 +
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#EEEEFF; padding:10px;">
 +
Hints:
 +
<div class="mw-collapsible-content">
  
  
====11. factorial.pl====
+
&nbsp;
 +
Remember to think about all types of outcomes when designing your conditions in if/else statements: a negative factorial is undefined, and both 0! and 1! are equal to 1. Use die(); rather than exit(); to indicate that an unexpected input has been entered that the program cannot handle. Both cause the program to terminate, but die(); allows you to enter an error message on program exit, e.g. die(“Negative factorial is undefined.”);. Use a for loop to multiply out the factorial of the input number, and use a variable to store the value of the factorial during intermediate steps in calculation.
  
 +
&nbsp;
 +
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#DDDDFF; padding:10px;">
 +
Code:
 +
<div class="mw-collapsible-content">
 +
 +
 +
&nbsp;
 
<source lang="perl">
 
<source lang="perl">
 
#!/usr/bin/perl
 
#!/usr/bin/perl
Line 603: Line 800:
  
  
 +
&nbsp;
 +
</div>
 +
</div>
 +
</div>
 +
</div>
  
  
 +
&nbsp;
  
====12. factRecurse.pl====
+
===factorial(recursive)===
  
 +
 +
 +
&nbsp;
 +
(OPTIONAL) ...the second way is to use a subroutine '''recursively''' to yield the factorial of a number. Try programming it this way as well.
 +
 +
&nbsp;
 +
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#EEEEFF; padding:10px;">
 +
Hints:
 +
<div class="mw-collapsible-content">
 +
 +
 +
&nbsp;
 +
Recursion means  a function calls itself. Such a subroutine or program needs defined “base cases”, for which the subroutine can return a value without having to call itself again (allowing the program or subroutine to terminate, otherwise it would just go deeper, and deeper...). The base cases for factRecurse are exactly the same as for factorial.pl – negative factorial should return an error, and both 0! and 1! should return 1. In place of the for loop used in factorial.pl, each recursion of the subroutine in factRecurse.pl performs one small step (the small step that would be performed with each iteration of the for loop) and then applies it to the next subroutine call.
 +
(e.g. $resultOfSomeStep + subRoutine($currentCall – 1)).
 +
 +
&nbsp;
 +
<div class="mw-collapsible mw-collapsed" data-expandtext="Expand" data-collapsetext="Collapse" style="width:90%; border:solid 1px; background-color:#DDDDFF; padding:10px;">
 +
Code:
 +
<div class="mw-collapsible-content">
 +
 +
 +
&nbsp;
 
<source lang="perl">
 
<source lang="perl">
 
#!/usr/bin/perl
 
#!/usr/bin/perl
Line 634: Line 859:
  
  
 +
&nbsp;
 +
</div>
 +
</div>
 +
</div>
 +
</div>
  
  
 +
&nbsp;
  
 
 
&nbsp;
 
 
<!--
 
<!--
==Exercises==
 
<section begin=exercises />
 
<section end=exercises />
 
 
 
&nbsp;
 
 
==Notes==
 
==Notes==
 
<references />
 
<references />

Latest revision as of 22:26, 25 October 2012

Perl programming exercises 2


Small programming exercises for an introduction to Perl.


 

Basic Perl Programming - Programming exercises

Boris Steipe acknowledges contributions by Jennifer Tsai, Sanja Rogic and Sohrab Shah.

Here are programming exercises that focus on translating a concept into a working script.

The preceding section covers a section I have called syntax examples ... they are simple tasks that ask you to write functioning code syntactically correct.


For each task you will find

  1. a description of the task your code should achieve;
  2. some hints how to go about solving it - which functions you might use or which strategy; and
  3. sample code for reference if you are stuck. Should you really need to look up the samples, carefully study the code, put it away and then write your own script from scratch, with different code and perhaps some variation in function. If you merely copy code, or read it with mild interest and move on, you will probably be wasting your time.
Don't be satisfied until you understand what you are doing.


Tasks

Hello World

 

Executable program

Write a Perl program helloWorld.pl that prints out "Hello World" (or whatever you fancy) to the terminal. Make your program executable (chmod u+x helloWorld.pl) so that you don't need to invoke the Perl interpreter explicitly from the command line (i.e. just "$ ./helloWorld.pl" should run it, you shouldn't need to type "$ perl helloWorld.pl").

 

Hints:


 

cat()

 

Keyboard input

Write a Perl program cat.pl that prints to the terminal a single line that you type at the keyboard.

 

Hints:


 

lc()

 

More keyboard input

Write a Perl program lc.pl that reads one or many lines from STDIN, converts them to lowercase and prints them to the terminal. Use this interactively, typing input (end by typing <ctrl>D), then use this by redirecting a textfile to your program, then "pipe" the output of the Unix "ls" command into your program.

 

Hints:


 

max

 

Condition

Write a Perl program max.pl that prompts for and reads two numbers from STDIN, and outputs the larger of the two numbers to the terminal. Remember to consider the case that the numbers may be equal.

 

Hints:


 

max (with subroutine)

 

Subroutine

Rewrite max.pl so the comparison is done in a subroutine: pass the two numbers as arguments into a subroutine and return the larger of the two. Such a program may be a useful framework for comparing two datasets with a non-trivial metric. Instead of simply picking the larger value, the subroutine could compare according to some sophisticated algortithm

 

Hints:


 

anagram

 

Array

Write a Perl program anagram.pl that reads a string from STDIN and returns ten random permutations of this string. This will require a number of concepts and techniques of working with arrays - defining an array, assigning values to an array, or to individual fields of an array, using a variable as an index to an array in order to read from or write to specific fields, and more. First split your string into individual elements of an array. Use a subroutine that randomizes this array by looping over every position of the array, and swapping the contents of this position with a randomly chosen other position of the array, except itself. Write this in pseudocode first. The Perl functions you will need are split(); and rand();.

 

Hints:


 

anastring

 

Substring calisthenics

Copy anagram.pl to a file named anastring.pl and use the Perl strlen(); and substr(); functions to permute the string (in place !) instead of shuffling fields of an array. Make a point of programming this incrementally step by step, writing output as you go along to make sure you are doing it right. Of course you could also shuffle using the split() and join() functions on a string ... but that would not be "in place".

 

Hints:


 

anastring (with commandline input)

 

Commandline arguments

Modify anastring.pl so you can pass the number of permutations to the program in the commandline ( via @ARGV ), make sure that the default is 1, if no argument is given. This tool could be part of a routine to generate random data to test statistical significance.

 

Hints:


 

sort

 

Sorting

Write a Perl program sort.pl that takes in strings (e.g. names) from STDIN, stores them in an array, sorts them in alphabetical order, using the Perl sort(); function and prints them out to the terminal.

 

Hints:


 

fastaParser

 

Hash (associative array)

Write a Perl program fastaParser.pl that takes in a FASTA file of any protein as input and outputs it as three-letter amino acid code separated by spaces to the terminal. Use a hash to store the mapping between the one-letter amino acid code and the three-letter amino acid code.

 

Hints:


 

factorial

 

Iteration and recursion

Write a Perl program factorial.pl that takes in a number as input and calculates the factorial of that number. Note that this can be done in (at least) two ways: the first way is to use a for loop in the body of the program...

 

Hints:


 

factorial(recursive)

  (OPTIONAL) ...the second way is to use a subroutine recursively to yield the factorial of a number. Try programming it this way as well.

 

Hints:


 

 

Further reading and resources