Connecting Tech Pros Worldwide Forums | Help | Site Map

Hashes, Static Variables, Recursive Functions, Serialization

KevinADC's Avatar
Expert
 
Join Date: Jan 2007
Location: Southern California USA
Posts: 4,091
#1   Jan 2 '09
This snippet of code provides several examples of programming techniques that can be applied to most programs.
  • using hashes to create unique results
  • static variable
  • recursive function
  • serialization

The code itself generates a list of strings comprised of random numbers. No number will be repeated within a string, and no string will be repeated within the list of strings. Following the code is a brief discussion of how the above programming techniques are used to achieve those requirements.

Expand|Select|Wrap|Line Numbers
  1. use warnings;
  2. use strict;
  3.  
  4. my $length = 7; # the amount of numbers per string
  5. my $max = 1000; # the number of strings
  6. my @strings; # array to store the strings
  7. for (1..$max) {
  8.    push @strings, rand_nums($length);
  9. }
  10. print "$_\n" for @strings;
  11. {
  12.    my %cache; # create a "static" variable
  13.    sub rand_nums {
  14.       my %local_cache; # create a new hash
  15.       my ($length) = @_; # the length of the random number string passed to the sub
  16.       my $serial = int(rand(49))+1; # get the first number for the serialized string
  17.       $local_cache{$serial} = 1; # store the first number in the hash
  18.       for (2..$length) {# start at 2 because we already have the first number
  19.          my $num = int(rand(49))+1; # get a new random number
  20.          redo if exists $local_cache{$num}; # redo the loop if the number already exists
  21.          $local_cache{$num} = 1; # store the number in the hash
  22.          $serial .= "-$num"; # append to the serialized string
  23.       }
  24.       rand_nums($length) if exists $cache{$serial}; # redo the function if the key already exists
  25.       $cache{$serial}=1; # store the new key in the hash (%cache)
  26.       return $serial;
  27.    }
  28. }
  29.  
Whenever you think unique with perl a hash is invariably going to be used. This is because the keys of a hash must be unique. I used two hashes, one to keep track of each string of numbers (%local_cache) to insure there are no repeated numbers in any one string, and another one to insure that all the strings are unique (%cache).

%cache is wrapped in a block {} around the function (rand_nums) to create a perlish version of a C static variable. Declaring it with "my" inside the block makes it lexically scoped to the function but hides it from the rest of the code/file. Since the code snippet above is not doing anything else this is not really necessary, but its an example of how you can create static variables with perl. Perl 5.10 also has a new feature that allows you to create static variables called state.

%local_cache is declared with "my" inside the function because we want to declare a new hash each time the function is called. This insures that each string of numbers has no repeated values. %cache insures that there are no repeated strings of numbers.

$length and $max could easily be used to accept some input to the script making those variables dynamic each time the script is run

Inside the rand_nums() function you see a call back to the function:

rand_nums($length) if exists $cache{$key};

This just tells perl to run the function again if the string already exists. The function runs again, produces another string of numbers and checks again if it already exists or not. This is a simple example of a recursive perl function. If the string of numbers does not already exist the code continues to run and eventually returns a string back to be added to the array @strings.

Something important to keep in mind when using a recursive function is to not introduce a condition that could cause infinite (or deep) recursion. The "warnings" pragma will warn you if such a condition occurs in your perl scripts. In the code above if you set $length to a small number, say 3, you can see for yourself what will happen.

I mentioned serialization at the beginning. Serialization is the joining together of arbitrary strings to make a single string. $serial will be the serialized string, which is the joined list of random number. It starts at this line:

my $serial = int(rand(49))+1; # get the first number for the serialized string

The string is serialized by using the concatenation operator together with the assignment operator:

$serial .= "-$num";

We end up with a string something like this:

3-22-45-9-11-33-48

That string is used as the hash key to make sure there are no duplicated strings in the final list. The reason we don’t join the keys of %local_cache to make the serialized string is because while hashes have no guaranteed order, they don’t have a random order. The resultant strings of random numbers created by joining the hash keys together would no longer be random but would favor the probability of numbers occurring at certain positions in the strings. You will end up with strings that have the same numbers in the same positions over and over even though no two strings will be duplicated.


A list of pragmas and perl builtin functions used in the code:

Perl functions :
Pragmas :
  • strict - Perl pragma to restrict unsafe constructs
  • warnings - Perl pragma to control optional warnings



KevinADC's Avatar
Expert
 
Join Date: Jan 2007
Location: Southern California USA
Posts: 4,091
#2   Jan 2 '09

re: Hashes, Static Variables, Recursive Functions, Serialization


Comments, corrections, discussions are welcome.
Kelicula's Avatar
Expert
 
Join Date: Jul 2007
Posts: 169
#3   Jan 17 '09

re: Hashes, Static Variables, Recursive Functions, Serialization


Documentation missing for "redo".
It's a very interesting function.

redo - perldoc.perl.org
KevinADC's Avatar
Expert
 
Join Date: Jan 2007
Location: Southern California USA
Posts: 4,091
#4   Jan 17 '09

re: Hashes, Static Variables, Recursive Functions, Serialization


Quote:

Originally Posted by Kelicula View Post

Documentation missing for "redo".
It's a very interesting function.

redo - perldoc.perl.org

Good catch, thanks.
KUB365's Avatar
Administrator
 
Join Date: Jul 2005
Location: Portland, OR
Posts: 974
#5   Feb 22 '09

re: Hashes, Static Variables, Recursive Functions, Serialization


Nice article kevin. ++
Reply