You have two orthogonal problems.
  1. How do I pick something randomly from a list if-and-only-if I haven't used it before?
  2. How do I preserve state between two runs of the same program?

The answer to the second is easy - use a DBM. The best DBM for this kind of task would be DBM::Deep because it allows you to have a Perl datastructure be backed by disk instead of RAM. All the standard Perl datastructure manipulators for hashes and arrays exist and are used just like normal.

The answer to the first is to maintain a list of unchosen items. Once an item is chosen, then you remove it from the list of choosable items and move on. Assuming that there aren't any duplicates, this is best implemented as a set which is usually implemented as a hash in Perl. So, something like:

my %set = ( # Populate this somehow. ); my @keys = keys %set; my $chosen_key = $keys[ rand @keys ]; my $chosen_value = delete $set{ $chosen_key };

Now, if your list of chosen items isn't discrete, then maintain a list of previously chosen items and disregard a choice until it doesn't exist. This is also implemented with a hash, but instead of calling it %set, one generally calls it %seen. Implementation left as an exercise for the reader.

Now, the hard part - doing the DBM bit. Let's say we have a discrete set as per the prior example. Go ahead and seed the DBM file as so:

my %set; tie %set, 'DBM::Deep' => { file => 'my_file.db' }; %set = ( # Populate as desired, nesting arrays and hashes as appropriate. );
Now, let's modify our prior example. With a DBM, it looks like:
my %set; tie %set, 'DBM::Deep' => { file => 'my_file.db' }; my @keys = keys %set; my $chosen_key = $keys[ rand @keys ]; my $chosen_value = delete $set{ $chosen_key };
Alternately, you can choose to use the OO interface which would look like:
my $set = DBM::Deep->new({ file => 'my_file.db', }); my @keys = keys %{ $set }; my $chosen_key = $keys[ rand @keys ]; my $chosen_value = delete $set->{ $chosen_key };
Note the difference between hash notation and hashref notation.

Oh - and if you need them, DBM::Deep also supports transactions and synchronous access.


My criteria for good software:
  1. Does it work?
  2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?

In reply to Re: Don't-Repeat-Myself code for improvement by dragonchild
in thread Don't-Repeat-Myself code for improvement by Cody Pendant

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.