Wednesday 23 April 2014

Loops and conditionals: While/until

This is going to be simple little post about the while statement. It's general format looks like this:

while (condition) {
    code block
}

As you can probably figure out, the code block is executed while the condition evaluates to true. As soon as the condition evaluates to false, the code block is passed over and the rest of the file is run. The conditions function exactly the same way as I wrote about in my if post, so if you need to brush up on what a condition is and how it works, go to http://www.perladventures.blogspot.co.uk/2014/04/ifelsifelse.html

Here's an example of how you can use while in your code:
1.   my $i = 5;
2.
3. while ($i > 0) {
4.     print "$i\n";
5.     $i--;
6. }
This will give output:
5
4
3
2
1

The condition is evaluated before the first iteration so if the condition is initially false, the code block will never be run.

Until

There's also a revers version of while. I've never actually seen it in real code before and it looks just as difficult as unless.

until (condition) {
    code block
}

This time, the code black runs while the condition evaluates to false
1.   my $i = 1;
2. my $j = 12;
3.
4. until ($i > $j) {
5.     print "$i\n";
6.     $i *= 2;
7. }
This will give output:
1
2
4
8

Again, the condition is evaluated before the code block is run. So if your condition initially evaluates to true, the code block will never be run.

The examples I've done are all to do with numbers but you can use pretty much anything you want.

Next in the loops and conditionals mini-series - loop controls

Thursday 10 April 2014

Loops and conditionals: For each

Arrays and lists and things like that are all very well, but we often need a way of going through each element sequentially to make use out of them - maybe to search for something or to do some function on each element. This is where for and foreach loops come in.

A for(each) loop goes through each item in an array or a list or anything else you want to iterate through for example numbers 1-10. In fact, if the thing you put inside the brackets returns a list, it can be iterated over.

It's general layout looks something like this:

for(each) (array/list/whatever) {
    code block
}

For or foreach?
I've just discovered that for and foreach are completely identical and do exactly the same thing. You can use them both interchangeably. The underlying code for both is exactly the same. This leads me to think why then, are there two different words for it, but unfortunately I don't think there is a real answer to it.
I wanted to find out which one programmers prefer and I asked around at work and it seems like the only reason they pick one over the other is convention. Most of the people I asked use for and foreach in the following way:

For is generally used if you don't have something specific to iterate through. You can initialise a variable, condition check and increment the variable.
1.   for (my $i = 1; $i < 9; $i++) {
2.     print "$i "
3. }
This just prints out numbers 1 to 8 with a space between each.

For those who are unfamiliar with the above -
my $i = 1 - initialising the variable to use.
$i < 9 - giving the variable a maximum or minimum size.
$i++ - showing how much to increment or decrement the variable with each pass of the loop - in this case, it means plus one.

Basically all of this put together means, there is a variable called $i with a value of one. Start with $i = 1 in the first pass of the loop and add one to it each time you go through the loop until $i is no longer less than 9, then exit the loop.


Foreach is often used if you are going through an array or list or hash and you want to go through the elements of each one. For example:
1.   foreach (@myarray) {
2.     print "$_\n";
3. }
This just goes through each item in the array and prints them out on individual lines.

You can however, swap the for and foreach around or you can use the same word for both usages, it's totally up to you but I think I'm going to stick with how I've described it as above.

The good thing about foreach loops in perl, which I haven't come across before, is that you don't have to explicitly say how big the array or whatever you're iterating through is and you don't have to tell it that you want to go to the next item once it's finished with the item it's on.

What is this $_?
In this case, it is a quick and anonymous way of referring to each individual item of the array, it's called the "default" variable. It represents the scalar that's being focussed on so in the case of a for loop, it's the list item or array item that's being currently looked at. It's kind of like using the word "it" in the English language - you know what you are referring to, but you're using a general word.

It is bad practice to directly alter the original array so instead you can assign the individual elements to a new variable as I've done below - $item refers to each individual array item:
1.   foreach my $item (@myarray) {
2.     print "$item\n";
3. }
You can also use foreach with hashes, it's very similar to arrays:
1.   foreach my $key (keys %myhash) {
2.     print "this is the key: $key\n";
3.     print "this is the value: ".$myhash{$key}."\n";
4. }
This will print out the statements followed by the key on one line and the value on the next for each of the items in the hash.
Note the "my" isn't completely necessary, because if you leave it out, the "my" will be implied anyway.

You need to write the word "key" inside the brackets before writing the name of the hash because what you are doing is getting a list of keys in the hash and then iterating over them. Within the code block, you can then use the key to get the values.

I then wondered about not just getting a list of the keys and iterating over them, but getting the keys and the values and iterating over them and I was told about "each". You can't really use it with a for loop and it looks something like this:
1.   while (my ($key, $value) = each %hash) {
2.     print "key is $key, value is $value\n";
3. }
As you can see you use a while loop, which I haven't covered yet but basically it just goes through all of the keys and values and prints them out.
A warning does come with using each - you need to make sure that nothing else in your program can is changing the hash you're iterating over because if changes happen during the while loop. You may end up skipping or duplicating entries.

Map
I think I have mentioned map before but this is definitely a place to write a reminder. It's just a slightly cleaner way of writing code that takes each member of an array/list and modifies or uses it in the same way to create a new list.
1.   my @new_array = map {
2.     print "this is the key: \n";
3.     print "this is the value: $item \n"
4. }

Thursday 3 April 2014

Loops and conditionals: Ifelsifelse

The next things on my list are conditionals and loops. I think that these concepts are fundamental to actually making any programming language work and without them, there wouldn't be much to do, especially when combined with conditional logic.

The first one is the if statement. It's basic structure is something like this:

if (condition) {
    code block
}

This evaluates the condition in the parentheses, and if it's true, the code block will be run and if it's false, the code block will be passed over and the rest of the file will be run.

Boolean Logic

How do I make the condition equal to true or false?
Perl doesn't actually have any specific true or false objects or identifiers so we have to make the condition evaluate to values that themselves are either true or false.

What evaluates to true or false?
Basically everything is true, apart from undef, "0", an empty string ("") and anything that evaluates to any of these.

The table below shows how you can get true or false values:

True False
"0.0" ""
" " "0"
1 undef
+ve integers 0 # converts to "0"
-ve integers 0.0 #computes to 0 and then converts to "0"
strings unassigned variable  #evaluates to undef

()  #empty list

("") #empty string in a list

You can put any of these as the condition, for example:

1.   if (7) {
2.     code block
3. }

1.   my $value = 0.0;
2. if ($value) {
3.     code block
4. }

The code block will run in the first example because 7 is a positive integer and positive integers evaluate to true. The code block will not run in the second example because 0.0 evaluates to false.

You don't have to put single values into the condition - you can also use boolean operators to make things more interesting and with these, you can make expressions that evaluate to true or false.


Boolean Operators Meaning
> Greater than (numerical)
< Less than (numerical)
== Equal to (numerical)
gt Greater than (string)
lt Less than (string)
eq Equal to (string)
! Not
&& And
|| Or

1.   my $temperature = 28;
2. if ($temperature >  25) {
3.     print "it's hot!";
4. }
1.   my $value = 4;
2. if ($value <  8  &&  $value > 5) {
3.     print "this number is between 5 and 8";
4. }
1.   my $string = "hello";
2. if ( ($string eq "hello") || ($string eq "hi") {
3.     print "hello there";
4. }

Of course you can put more interesting things inside the code blocks than just a print statement, but you get the idea.

You can also experiment with making things more complicated and incorporate as many ands and ors as you want and and combination of boolean operators or do crazy things like XOR and NAND.

To use not, you just put the exclamation mark in front of the expression you want to evaluate:
(!($string eq "hello"))
I think the inside brackets are optional but it makes things clearer and shows that you want to negate the whole of the expression rather than just the variable.

Note
If you try to compare two numbers using the string equal to operator (eq) the numbers will be stringified and then compared. If your two numbers are the same, the condition will evaluate to true as the strings will be the same. If the numbers are different, you will get false.

If you try to compare two strings using the numerical equal to operator (==) you will get warnings but it will always evaluate to true, even if the strings are not the same. This is because strings are evaluated as 1 and then you will be comparing two 1's.

Else

Sometimes you want something to happen if the if condition isn't satisfied. You can then add extra code to say what you want to do if the if condition evaluates to false by using else. The else immediately follows the if as follows:

if (condition) {
    code block
}
else {
    code block
}

This way some code will always be run no matter what the condition evaluates to. If it evaluates to true, only the first code block is run, if it evaluates to false, only the second code block is run. Then the rest of the file is then run as normal.

This example could work in a shop selling alcohol (can you tell I used to work in a supermarket?):

1.   if ($customer_age > 17 {
2.     print "sale authorised";
3. }
4. else {
5.     print "sale denied";
6. }

Elsif

What happens if you want to put multiple ifs together? Say that you want to test one condition, and if it's not satisfied, you want to test another condition. This is where elsif comes in, and for reasons unknown to me, it is spelt with a missing 'e'. Excellent.

if (condition) {
    code block
}
elsif (condition) {
    code block
}

If neither of the conditions are satisfied, neither of the code blocks will be run. If the first and the second condition are satisfied, only the first code block will be run because the second conditions is only evaluated if the first condition is not true.

For example:
1.   my $x = 50;
2. my @small_numbers;
3. my @medium_numbers;
4.
5. if ($x < 101) {
6.     push(@small_numbers, $x)
7. } elsif ($x < 201) {
8.     push(@medium_numbers, $x)
9. }

This code is just looking at the number and putting it into an array of small or medium numbers. So here I've defined small as 100 or less and medium as 200 or less. If the number is larger than 200, nothing will happen. I know this makes no sense in the real world but I think it works as an example.

You can write it like this or you can add an "else" onto the end if neither of the two conditions are satisfied.

You can chain as many elsifs as you want together but only on else can be put onto the end.

I couldn't think of a real life example so, again, here are a bunch of numbers:

1.   my $x = 5;
2. my @small_numbers; 
3. my @medium_numbers;
4. my @large_numbers;
5. my @very_large_numbers;
6.
7. if ($x < 4) {
8.     push (@small_numbers, $x);
9.  } elsif ($x < 8) {
10.     push (@medium_numbers, $x);
11.  } elsif ($x < 20) {
12.     push (@medium_numbers, $x);
13.  } else {
14.     push (@very_large_numbers, $x);
15.  }

This code is just looking at the number and putting it into an array of small, medium, large or very large numbers. So here I've defined small as below 4, medium between 4 and 7, large between 8 and 19 and very large as 20 and above. I know this makes no sense in the real world but I think it works as an example.

Again, make sure you spell elsif properly!!!


Unless

This one is the exact opposite of if and when I see it, it always messes with my head and I have to think about it for a moment - every single time! I think that it's used when it looks cleaner to use rather than having double negatives everywhere or having lots of ands and ors.

unless (condition) {
    code block
}

Here the code block only runs if the condition is not satisfied:
1.   unless ($age < 18)
2. {
3.     print "Sale approved";
4. }
This just means that sale approved will only be printed if the customer is 18 or over.