Conditionals, Comparisons and Truth


Computers would be totally useless devices if they could not could execute commands subject to conditional logic. At the heart of programming and computers is execution when something happens to be true.


If


  • The "if" construct allows execution of one or more statements only if a condition is met.

if (something is TRUE){
   #do things here
}

For example:

print "Please enter your age\n";
my $user_age=<STDIN>;
chomp $user_age;
 
if ($user_age < 30){
  print "Under 30? You're just a baby!\n";
}

  • For numerical comparisons:
    • == (equal?)
    • != (not equal?)
    • < (less than?)
    • > (greater than?)
    • <= (less than OR equal?)
    • >= (greater than OR equal?)

print "Please enter your age\n";
my $user_age=<STDIN>;
chomp $user_age;
 
if ($user_age < 0){
  print "I'll talk to you after you are born\n";
}
 
if ($user_age == 0){
  print "Welcome to the world!\n";
}
 
if ($user_age >= 1){
  print "It's never to early to program!\n";
}
 
if ($user_age != 64){
    print "You are not the perfect age\n";
}

Watch out for the typical assignment instead of equality test error ("=" instead of "==").

  • For string comparisons:
    • eq (equal?)
    • ne (not equal?)
    • lt (less than?)
    • gt (greater than?)

print "Please enter your name\n";
my $user_name=<STDIN>;
chomp $user_name;
 
if ($user_name ne "Jody"){
    print "You are not Jody, too bad for you.\n";
}
 
if ($user_name gt "Jody"){
  print "You come way after Jody!\n";
}
 
if ($user_name lt "Jody"){
  print "You are much less than Jody!\n";
}
 
if ($user_name eq "Jody"){
  print "Yey!  You are Jody!  It's an honor to meet you.\n";
}

Another common error is performing a numerical comparison instead of a string one.
if ($user_input=="Jody") should be if ($user_input eq "Jody")

Let's get a bit more technical.

Are you ready for the TRUTH?


  • 0, undefined, and null string are FALSE.
  • Everything else is TRUE.

The importance of the above is that not only can you use as conditionals numerical and string comparisons, but variables, strings, numbers, functions can also be inside the "if", "while", "for" constructs.

The following code illustrates the true and false scenarios, with comments indicating true/false.

my $variable;
 
if ($variable){
    print "inside\n"; #false
}
 
$variable = '';
if ($variable){
    print "inside\n"; #false
}
 
$variable = 0;
if ($variable ){
    print "inside\n"; #false
}
 
$variable = 54;
if ($variable ){
    print "inside\n"; #true
}
 
$variable = 5;
if ($variable-5){
    print "inside\n";
}
 
if (0+1){
    print "inside\n";
 
}

  • "not" reverses the true/false value

my $variable=0;
 
if (not $variable){
    print "inside\n"; #true
}
 
$variable = 54;
if (not $variable ){
    print "inside\n"; #false
}
 
 
if (not 5 < 4){
    print "inside\n"; #true
}


  • String or number makes a big difference.

my $variable=00;
 
if ($variable){
    print "inside\n"; #false
}
 
$variable="00";
 
if ($variable){
    print "inside\n"; #true
}


  • Looking under the hood, any numerical or string comparison returns true (1) or false (undefined).

my $num2=2;
 
my $comp_variable = ($num1==$num2);
 
print $comp_variable, "\n";
 
 
$comp_variable= ($num1<=$num2);
 
print $comp_variable, "\n";

Boolean Operators: and, or


Combining conditionals gives us a lot of power.

print "Please enter your name\n";
my $user_name=<STDIN>;
chomp $user_name;
 
print "Please enter your age\n";
my $user_age=<STDIN>;
chomp $user_age;
 
if ( ($user_name eq "Jody") and ($user_age>100) ){
    print "You're not the right Jody!\n";
}
 
if ( ($user_name eq "Jody") and ($user_age > 100 or $user_age < 10) ){
    print "You're not the right Jody!\n";
}
 
if ( ($user_name eq "Jody") and ($user_age <= 100) and ($user_age >= 10) ){
    print "You might be the right Jody!\n";
}

Use parentheses!!!!

($num1 and $num2 or $num3 and not $num1 < $num3) is unintelligible.

if/else/elsif


While you now have all the logic power with "if" and "and/or", lot's of conditions in the code can be very confusing.

print "Enter your age:\n";
chomp( my $age = <STDIN> );
 
if ( $age < 0 ){
    print "This is not valid\n";
}
 
if ( $age > 0 and $age <= 2 ){
    print "You are eligible\n";
}
 
if ( $age >= 3 and $age <= 8 ){
    print "You are not eligible\n";
}
 
if ( $age > 9 and $age <= 12 ){
    print "You are eligible\n";
}
 
if ( $age > 12 and $age < 15 ){
    print "You are not eligible\n";
}
 
if ( $age >= 15 and $age <= 27 ){
    print "You are eligible\n";
}
 
if ( $age > 27 and $age <= 130 ){
    print "You are not eligible\n";
}
 
if ( $age > 130){
    print "This is not valid\n";
}
 
# Hello, Carpal tunnel
 
__END__

You get enough repetitive stress injury from pipetting. So, here's to simpler life.

print "Enter your age:\n";
chomp( my $age = <STDIN> );
 
if ( $age < 0 or $age > 130 ){
    print "This is not valid\n";
}
elsif ( ($age > 0 and $age <= 2) or ( $age > 9 and $age <= 12 ) or
        ( $age >= 15 and $age <= 27) ) {
    print "You are eligible\n";
}
else {
    print "You are not eligible\n";
}

This construct is very useful and very flexible. You can have "elsif" without "else" or "else" without "elsif".

Exercises


Problem1

  • Modify the script from Problem2 in the morning session to also print the minimum and maximum user-entered numbers.

Problem2

  • Modify the script from Problem3 so that it no longer requires user input to be in the order small, large.


Problem3

  • Your program will accept inputs from the user.
  • For each input, you will attempt to determine whether the user input was a string (something that had alphabets or symbols in it) or an integer (something that had just digits in it).
  • You will then inform the user of what you thought the input was, and accept the next input.
  • Your program will exit when the user types in 'exit' or 'QUIT'.
Hints

Problem4

  • This program will emulate some functionality of the UNIX utility head.
  • Prompt the user to enter a filename
  • Prompt the user to enter a number n
  • Read the top n lines from the file and print them out.
  • Run your program with n=10 on the cerevisiae genome.


Problem5

  • Now that you have the S.cerevisiae genome, compute its base composition.
  • Your script will open a user-specified multi-fasta file.
  • If you come across any characters other than ACGT, keep a total counter for them.

%A: 0.309011284080829
%C: 0.191674621749383
%G: 0.19130281845619
%T: 0.308011275713598
non-DNA characters: 0

Hints

Problem6

  • Prompt the user for a DNA string
  • The program will produce a reverse-complemented version of the input sequence.

Bonus


Bonus1

  • For our learn-a-perl-function-by-yourself exercise of the day, we have .... rand (google, google, google).
  • You will be attempting to test whether the random number generator in Perl is truly random.
  • You will generate some number of random integers (in the range 0-9) and see if they are evenly distributed among the five bins of size 2 : 0-1, 2-3, 4-5, 6-7, 8-9.
  • Your program will continuously print lines to the screen in the following format:

tested: 5000; 0-2: 999; 2-3: 1001; 4-5: 998; 6-7: 1002; 8-9: 1000
tested: 5001; 0-2: 1000; 2-3: 1001; 4-5: 998; 6-7: 1002; 8-9: 1000
tested: 5002; 0-2: 1000; 2-3: 1002; 4-5: 998; 6-7: 1002; 8-9: 1000
tested: 5003; 0-2: 1000; 2-3: 1001; 4-5: 998; 6-7: 1003; 8-9: 1000
....

  • Your program will only exit when you interrupt it by using the ^C (Control+C) sequence.
  • Does it look random?
Hints

Bonus2

  • This program accepts two strings as input. One of these is the 'target', the other is the 'pattern'.
  • It looks for (partial or full) matches of the pattern within the target.
  • It prints out the position within the target at which each match begins, the matching portion, and the length of the match.
  • Matches need not be "full-length" ie.

target:..'Jabberwockies do not jabber, they jab. They have a fear of door jambs and rock-hard abs.'
pattern:.'jabberwock'

OUTPUT:
0,Jabberwock,10
21,jabber,6
34,jab,3

  • Clearly, the matching is case-insensitive
  • Notice that 'jamb' did not match. The first mismatch you find will end a match.
  • Also notice that 'ab' from 'abs' did not match. Matches must begin at the first position in the pattern. Obviously they may begin anywhere within the target.
  • We are only interested in matches >= Length 2.
  • Once you have this information, use UNIX utilities to sort the output and find the longest match.

Hints

Hints




Hints3

  • It's easier to test for all the digits than for all the other characters
  • A single non-digit makes something a string
  • You should be using loops and substrings here, not trying to be clever with numeric versus string comparisons




Hints5

  • You will need to walk through the sequence and look at each character
  • There are length($string) characters




HintsBonus1

  • The while loop exits when its condition becomes false
  • Try something that is always true for an infinite loop
  • What is truth?
  • 1 is always true
  • Try while(1)




HintsBonus2

  • You will need to test for a potential match at each position in the target
  • You will need to compare each of the characters of the pattern to the characters starting from the position in the target where you're checking for a match.
  • You will need to keep track of how many matches you have found so far (starting from 0). If you find a single mismatch, set this number to be -1. If this number has been set to -1 because of a previous mismatch, you will no longer increment it even you find other matches. If you think about it, a positive value of this count when you run out of pattern characters to compare, meant you had a match. You need a value of atleast 2.
  • Because you need to walk through the entire pattern for every position in the target, you will need two for loops, one nested inside the other.
  • Case-insensitive comparisons are possible if you lowercase (perldoc lc) the two things you're comparing.
  • sort with the right delimiter will allow you to sort comma-separated values. man sort



Solutions