- 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
- use warnings;
- use strict;
- my $length = 7; # the amount of numbers per string
- my $max = 1000; # the number of strings
- my @strings; # array to store the strings
- for (1..$max) {
- push @strings, rand_nums($length);
- }
- print "$_\n" for @strings;
- {
- my %cache; # create a "static" variable
- sub rand_nums {
- my %local_cache; # create a new hash
- my ($length) = @_; # the length of the random number string passed to the sub
- my $serial = int(rand(49))+1; # get the first number for the serialized string
- $local_cache{$serial} = 1; # store the first number in the hash
- for (2..$length) {# start at 2 because we already have the first number
- my $num = int(rand(49))+1; # get a new random number
- redo if exists $local_cache{$num}; # redo the loop if the number already exists
- $local_cache{$num} = 1; # store the number in the hash
- $serial .= "-$num"; # append to the serialized string
- }
- rand_nums($length) if exists $cache{$serial}; # redo the function if the key already exists
- $cache{$serial}=1; # store the new key in the hash (%cache)
- return $serial;
- }
- }
%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 :