Secure Email, Web and Form Solutions     +1 800.441.6612
LuxSciLuxSci
Secure Email,
Web and Form Solutions
Call: 800-441-6612
Int'l: +1 814-870-9250
sales@luxsci.com
support@luxsci.com

Introduction to Internet Programming: Part 5 – Perl Data Part I – Lists

Share Post:
More...

This article is Part 5 of our series on Internet Programming. See the Introduction and Part 1, Introduction to HTML. This article covers the Perl "list" data type.

5.1 Motivation

Using "scalar" variables we have been able to store any single datum into a named box -- strings, numbers, dates, boolean values, etc. These add a great versatility and power that makes programming at all useful. However, there are many instances where you need to store lots of information in lots of variables and the fact that each variable has a different name makes it difficult to simplify your program with loops and other devices.

For example, in the homework for lesson 3, you had to write a MadLib that would ask the user for 8 different words with 8 different prompts. You might have written something like this:

print "Enter a noun:";
$word1 = <STDIN>;
chomp($word1);

print "Enter an action verb:";
$word2 = <STDIN>;
chomp($word2);

And so on until you had asked 8 questions. This works fine, but seems pretty redundant as you are essentially doing the exact same thing eight times in a row, with only the contents of the prompt and the name of the variable are changing. This is where Perl's "list" variable type comes in handy. A list is a named variable with numbered "compartments" where you can store data. Thus a list is a numbered collection of variables of the (scalar) type we have been using so far.

5.2 Making a List all at Once

Let's demonstrate the one syntax for making a list in Perl, then explain all the nuances:

@prompts = ( "Enter a noun",          "Enter an action verb",
             "Enter a person's name", "Enter a place",
             "Enter an action verb",  "Enter a woman's name",
             "Enter an occupation",   "Enter a type of animal" );

Here we have made a list to contain the prompts for the eight MadLib entries we need. Starting from the left, the name of the list is prefixed with an at-sign ("@"). Perl knows that you mean a list and not a regular variable because you have the at-sign there and not the dollar sign. The names of lists follow all the same rules as names for other variables (with the exception of the prefix). One interesting thing to note is that the names of lists are independent of the names for regular (scalar) variables, So it you have a list @x and a normal variable $x, then they will be completely different, non-ambiguous and independent variables! It is, however, not recommended to use the same name for different types of variables as it can lead to confusion on the part of the programmer and inadvertent bugs.

This list is formed as a comma-delimited set of items inside parenthesis. The individual items can be strings, numbers, the results from an expression, etc. Since spaces don't matter outside quotation marks in Perl, we use them to line up our list elements to make our program more readable -- not necessary, but nice.

5.3 Storing and Retrieving Individual Items From a List

To retrieve a value from a list, we need to know what index in the list the item is located at. Lists created as in the example above start at index ZERO, so the first item is list element zero an the last one is list element seven. To print the value of list element 2, we would

print $list[2];    # Prints the string "Enter a person's name"

This prints the list element at index "2" which is the third item in the list. The syntax may seem a little odd... why is there a $ prefix there is we are dealing with a list? Well, lets start from the other side. You specify the list element you want by tacking on a suffix to the name of the list of the form "[index]", where index can be an integer number, like "[2]", or a number stored in a variable, like "[$index]", or the result of a function call, like "[sqrt(4)]". Now, as to why the prefix is suddenly a dollar sign, think about what we are doing -- we had a list of items and the list uses a prefix @; we are getting back a single item (and not a list) which is essentially a regular variable (because that is how it behaves). Since each item in your list is a regular variable, you refer to them using the dollar sign! (If you used the at sign prefix accidently, you would usually still be OK, but it has a slightly different meaning that may cause you problems in certain circumstances, so use the dollar sign...)

So, you can retrieve an element from a list and use it wherever you could use a normal variable. This includes assignment. I.e.


@list = ("a","b","c","d");

print "$list[0]\n";

$list[1] = "$list[0] - 123 - $list[1]";

$i = 2;

if ($list[$i] eq "c") {
   print "It's still 'c'!\n";
   }

Some quick facts about lists:

  • Use list items just like you use normal variables
  • If you assign something to an index of a list that has never been used, then the list will automatically make room for it, so "$list[1000] = 33.4;" is OK, even if our list only had 4 elements in it before! All the elements from index 4 to 999 are still "undefined", but available for use.
  • If you try to retrieve an element whose index isn't in the list, or whose value has not yet been set, i.e. $list[999], this is the same as trying to retrieve a value from a regular variable that you have never used. Numerically, the result is treated as ZERO; lexically, it is treated as an empty string. If you want to see IF the value has not been defined, use the undef keyword in a lexical comparison:
       if ($list[500] eq undef) { print "Not Defined"; }
       if ($list[500] ne undef) { print "Defined!"; }
       
  • You can have as many items in a list as you want. You never have to worry about managing the memory yourself.
  • You don't have to initialize a list with an assignment like "@list = (1,2,3);" -- you can just start assigning values using the "$list[$i] = 3;" type of assignment syntax.
  • If you have a list and you want to empty it, assign an empty list to it:
            @list = ();  ## Makes the list empty
            

5.4 Some Simple List Examples

Let's complete the MadLib using lists:

@prompts = ( "Enter a noun",          "Enter an action verb",
             "Enter a person's name", "Enter a place",
             "Enter an action verb",  "Enter a woman's name",
             "Enter an occupation",   "Enter a type of animal" );

@answers = ();

## Get their answers for all questions

for ($index = 0; $index < 8; $index = $index + 1) {

   ## Loop until they type something in (and don't just
   ## hit Enter

   do {
      print "$prompts[$index]: ";  # Display prompt
      $answers[$index] = <STDIN>;
      chomp( $answers[$index] );
      } while ($answers[$index] ne "" );

   }

## display their answers back -- You could replace
## this look with the actual display of the MadLib
## text.

for ($index = 0; $index < 8; $index = $index + 1) {
   print "Answer $index is '$answers[$index]'\n";
   }

Finding the Length: Very often you want to find the length of a list (i.e. the number of variables in it), or a scalar (i.e. the number of characters in it). For regular variables (scalars), you can use the length command. For lists, you use a special syntax that returns the index of the last item in the list. So, for @list, $#list is the "index of the last element in the list. This is "0" if the list has 1 element, "5" if the list has six elements and "-1" if the list has zero elements. So, the number of items in any list is found by adding one to this number, i.e. "$#list + 1":

$input = <STDIN>;    ## Assume the user types "Joe"
                                ## then presses [Enter]
print $input;                   ## Prints "Joe\n"
print length($input), "\n";     ## Prints 4 (the "\n" is 1 character,
                                ##    a linefeed)

chomp();                  ## Delete all linefeeds
print length($input), "\n";     ## Prints 3

@list = ("a","b","c","d");
$length = $#list+1;               ## $length = 4
for ($i=0; $i<$length; $i++) {
   print "$list[$i]\n";
   }

print $list[ $#list ], "\n";    ## Print the last list item.

A New Loop: Since one of the most common uses of lists is to iterate over the elements, Perl has a special loop to do just that. It is a version of the for loop:

@list = ("a","b","c","d");
for $item (@list) {
    print "$item\n";
    }

This type of for loop iterates over all items in your list, @list, and assignees the value of each item to $item in turn, then executes the statements inside the curly brackets. In this way, you do not need to know the length of the list, keep track of the current position in the list, or use the [index] notation to read the list's elements. The disadvantages of this type of loop are: 1. Assigning or changing the value of the variable $item will not affect the value actually stored in the list itself, as $item only contains a copy of that information, and 2. you don't know what index in the list you are at, unless you are keeping a separate count, which would defeat much of the benefit of using this form of loop, anyway. We will see more examples of this type of loop below.

5.5 Special Functions for Lists

Perl has many functions designed just for manipulating your lists. Here we shall discuss a few of the more useful and ubiquitous ones.

push: The push function allows you to add an element to the end of a list (to "push" an element onto the end). For example, if you have a list of 5 elements and you push a new one on to list, it will become the 6th element (at index 5), i.e.

@list = (3.1415, 1.414, 2.333);  # No quotes needed for numbers.

push(@list, 77);

print $list[3];    # Prints "77"

The syntax of push is that it takes 2 arguments separated by a comma (actually, this is a list of arguments, but we'll get back to that in a later lesson). The first argument is the list you want to push on to and the second argument is what is pushed.

pop: The pop function is the opposite of push. It removes the last item from the list and returns it to you. After you use pop, your list is smaller. If your list is already empty and you use pop, it will return a value of undefined (undef).

@list = (3.1415, 1.414, 2.333);  # No quotes needed for numbers.

$x = pop(@list);  # Remove and return the last item

print "$x\n";     # Prints "2.333\n"
print "$list[2]";   # Prints "" since there is nothing there!

shift: The shift function is like the pop command, but instead of removing the last element from the list, it removes the first element in the list and shifts all the other elements down one index. It then returns to you that element that was removed. If your list is already empty and you use shift, it will return a value of undefined (undef).

@list = (3.1415, 1.414, 2.333);  # No quotes needed for numbers.

$x = shift(@list);  # Remove and return the first item

print "$x\n";     # Prints "3.1415\n"
print "$list[2]";   # Prints "" since there is nothing there!
print "$list[0]";   # Prints "1.414" since this is the new 1st item.

join: The join command does not alter a list like those above; it allows you to make one long string out of all the elements in your list. You give join a list and a delimiter string. join returns to you a string containing all elements of your list, where each element is separated from the next with a copy of your delimiter string. I.e.

@list = (3.1415, 1.414, 2.333);  # No quotes needed for numbers.
$x = join(", ", @list);
print $x;               # Prints "3.1415, 1.414, 2.333"
print join("|",@list);  # Prints "3.1415|1.414|2.333"
print join(".",@list);  # Prints "3.1415.1.414.2.333"

Clearly, join is very useful when you want to convert a list into a string for display or for storage in a normal variable. However, if you want to be able to convert your string back to a list later, be sure that the delimiter you use cannot be confused with any of the text that is in the list elements; i.e. see the last print statement above where we join the elements together with a period. In the output, there are more periods than delimiters and it is ambiguous where one item begins and ends. Choose you delimiters wisely.

split: The split command is the opposite of the join command. It takes a delimiter and a string and returns to you a list containing all of the pieces of the string between the delimiters. If there are no matching delimiters in the string, then you get a list containing only 1 item -- the original string!

@list = ();     ## An empty List
print join(", ",@list); ## Prints "" -- the list is empty!

$x = "3.1415|1.414|2.333";
@list = split("|",$x);

print join(", ",@list); ## Prints "3.1415, 1.414, 2.333"
print $list[2];         ## Prints "2.333"

@list = split("--",$x);  ## There is no "--" in $x!
print join(", ",@list);   ## Prints "3.1415|1.414|2.333"
print $list[0];           ## Prints "3.1415|1.414|2.333"
print $list[1];           ## Prints "" -- the list has only 1 elet.

5.6 Useful Examples

A list within a list using split and join. Hint -- look at this when doing your homework!

# A list of people and information about them
# Each person is one item in the list
# The information about them is in a "|" delimited string...

@info = ( "John Smith|678-564-2889|28",
          "Karen Green|599-234-1234|19",
          "Jake Hagerson|890-111-0352|22" );

for ($i=0; $i <= $#info; $i++) {
   @data = split("|",$info[i]);  # Get the individual info.
   print "Name:   $data[0]\n";
   print "Phone:  $data[1]\n";
   print "Age:    $data[2]\n\n";
   }

Creating an array from user input:

print "Enter a series of numbers, one per line.\n";
print "Enter 'exit' when you are done.\n\n";

@numbers = ();    ## Empty array

do {                         ## Do loops perform the statements

   print "Number (or 'exit'):";

   $input = <STDIN>;         ## FIRST, then check the condition.
   chomp($input);

   if (lc($input) eq "exit") {  # Exit the loop
      last;
      }

   push(@numbers, $input);  ## Add to the list!

   } while (1==1);    ## Always TRUE


if ($#numbers + 1 == 0) {       ## No Numbers?
   print "No numbers entered. Exiting.\n";
   exit;
   }

## Calculate the average

$sum = 0;
for $n (@numbers) { $sum = $sum + $n; }
$average = $sum / ($#numbers + 1);

print "The average is $average\n";

## Calculate the standard deviation

if ($#numbers == 0) {       ## Only 1 number?
   print "Not Enough information to calculate a\n";
   print "standard deviation\n\n";
   exit;
   }

$stddev = 0;
for $n (@numbers) {
   $stddev = $stddev + ($n - $average) ** 2;
   }
$stddev = sqrt($stddev / $#numbers);

print "The Standard Deviation is ";
print "$stddev\n";

5.7 Your Homework

For today's homework, you are going to generalize homework assignment #1 from lesson 4 -- the multiple choice question. You must do the following:

  1. Have 2 or more multiple choice questions
  2. Store the questions in a list. (I.e. 2 questions will be a list containing 2 strings, the statement of each question). Do not include the possible answers here. I.e. A question might be "On what day in December is Christmas celebrated?". See Section 5.2 for how to make this list.
  3. Store the answers to the questions in another list, where the possible answers that you will display to the user are delimited from each other by some character like "|". So, for the Christmas question, your answer string might be
    "December 12th|December 17th|December 25th|December 31st". (You can use split to convert this into a list for nice printing to the user. See the first example in Section 5.6)
  4. Store the correct answer to each question in another list. I.e. if we are asking these questions by letter, you might use the strings in #3 and #2 to display something like:

    On what day in December is Christmas celebrated?
    A. December 12th
    B. December 17th
    C. December 25th
    D. December 31st
    Enter your answer:
    The answer would be "C". This would be the value stored in the appropriate item in the answer list.
  5. Have your script ask the user each of the questions in turn (read your question and answer lists in a loop, display the question, split and display the possible answers, get the user's answer and compare with the actual answer.)
  6. Don't tell the user if he/she got the answer right or wrong, just remember this fact by storing it in another list (think push).
  7. After all the questions have been asked and answered, tell the user which ones he/she got right and wrong and tell them what percentage they got correct.

Similar Posts:

Share:
More...

One Response to “Introduction to Internet Programming: Part 5 – Perl Data Part I – Lists”

  1. Introduction to Internet Programming Part 6: Perl Data Part II – Hashes | LuxSci FYI Says:

    [...] you are already familiar with lists from Lesson 5, it is easiest to show you examples of using a hash and explain how it is different from how you [...]

Leave a Comment

You must be logged in to post a comment.

Security Certifications TRUSTe EU Safe Harbor Thawte Extended Validation SSL Certificate McAfee Secure Authorize.net Merchant