Having too much time on my hands recently, I wrote this article. I didn't put a whole lot of effort into it but hopefully its not too terrible. Any comments or additions/corrections are welcome.
<Begin article>
A code snippet that will generate n numbers of strings of n length. No string will repeat a number and no string will be repeated. The code produces a list of strings of numbers something like this:
49-3-13-2-12
38-22-3-36-44
22-32-46-30-7
22-39-18-30-47
See below for a discussion of the code.
The reason I posted this snippet is because there is a lot going on and the same logic can be applied to a wide variety of requirements. While there are no indepth explanations the discussion touches on a few important subjects:
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($leng th) 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.
Backing up a few lines in the snippet, you will see this line:
$local_cache{in t(rand(49))+1} = 1;
This is an example of how perl automatically converts an expression into a string when you put the expression inside the curly brackets when defining a hash key. Perl will convert the expression into a string that equals whatever random number the expression returns. See the rand function link below to understand how rand works.
Another line of the code that is of interest is this one:
my $key = join '-', keys %local_cache;
It joins the keys of the %local_cache hash to make a string to be used as a hash key in the %cache hash. Joining a list of strings together like this to create a single string is called serialization. Its important to note that the string when serialized does not put the numbers in the order that the code generated them. Thats because hashes are unordered lists. If you needed the strings to be in the same order the code generates the numbers you would need to use an ordered list, an array, to temporarily store the numbers before serializing them into a hash key.
I think the comments in the code snippet help describe what is happening in the code but if anyone has questions or comments please post them.
A list of pragmas and perl builtin functions used in the code:
Perl functions :
Pragmas :
<End Article>
<Begin article>
A code snippet that will generate n numbers of strings of n length. No string will repeat a number and no string will be repeated. The code produces a list of strings of numbers something like this:
49-3-13-2-12
38-22-3-36-44
22-32-46-30-7
22-39-18-30-47
See below for a discussion of the code.
Code:
use warnings;
use strict;
my $length = 5; # 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
$local_cache{int(rand(49))+1} = 1; # get the first number
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
}
my $key = join '-', keys %local_cache; # make a hash key by serializing (converting to a string) the numbers
rand_nums($length) if exists $cache{$key}; # redo the function if the key already exists
$cache{$key}=1; # store the new key in the hash (%cache)
return $key;
}
}
- recursive function
- serialization
- static variable
- using hashes to create unique results
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($leng th) 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.
Backing up a few lines in the snippet, you will see this line:
$local_cache{in t(rand(49))+1} = 1;
This is an example of how perl automatically converts an expression into a string when you put the expression inside the curly brackets when defining a hash key. Perl will convert the expression into a string that equals whatever random number the expression returns. See the rand function link below to understand how rand works.
Another line of the code that is of interest is this one:
my $key = join '-', keys %local_cache;
It joins the keys of the %local_cache hash to make a string to be used as a hash key in the %cache hash. Joining a list of strings together like this to create a single string is called serialization. Its important to note that the string when serialized does not put the numbers in the order that the code generated them. Thats because hashes are unordered lists. If you needed the strings to be in the same order the code generates the numbers you would need to use an ordered list, an array, to temporarily store the numbers before serializing them into a hash key.
I think the comments in the code snippet help describe what is happening in the code but if anyone has questions or comments please post them.
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
<End Article>
Comment