If item "foo" gets written as the first item in the file at iteration $N and then as the last item in the file at iteration $N+1, then "foo" will be returned twice in a row, which violates 'If I chose "foo" recently, I shouldn't use it again.'
My method of doing this is to permute the list and store it (probably in a database). When I need a new item, I pick a random number ($R) between 0 and $N where $N is a fraction of the size of the list and pick the $R'th least recently used item and mark it as the most recently used item.
One way to record which was most recently used is to put a timestamp in the records in the DB. Then picking the $R'th least recently used item can be done with a simple SQL query using "ORDER BY lastused LIMIT $R,1" (or the equivalent supported by your particular DB) and marking that item "most recently used" is a simple update to the timestamp.
The initial permutation of the list can be done by assigning each timestamp to a random time of day "yesterday".
| [reply] |
That's a good point, and an interesting solution provided that the number of IDs is small, but horribly expensive if the number of Ids is much more than the 8 shown.
40 thousand entries for the 8 IDs shown is managable, but if the number rises to 15 then wouldn't you need something like 70 terabytes to store the permutations?
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] |
No. My solution uses one DB record per ID. I don't try to store in a DB all possible permutations. I just put one record per item in the DB and "permute" their initial order, such as by setting the "lastused" field for each record to be some random time of day "yesterday", as I mentioned.
| [reply] |
I'm not actually working with a finite, fixed number at all. I should have said.
I'm using ids which come from an external source over which I have no control.
Also, there's no requirement to use them all up before repeating. Just that I shouldn't re-use the same one twice or more in a row.
($_='kkvvttuu bbooppuuiiffss qqffssmm iibbddllffss')
=~y~b-v~a-z~s; print
| [reply] |
Simplify your life.
"there's no requirement to use them all up before repeating. Just that I shouldn't re-use the same one twice or more in a row"
So you really don't need to keep track of anything more than the last one used.
I would use a simple text file with a single line containing the last value used. Read the last value from the file when you start, randomly select a values from your list until you get a 'new' value that doesn't match the previous (hopefully on the first try), then write the new value back to the file, replacing the previous one.
To do anything more would simply be a case of swating a mosquito with a with a lazer guided cruise missle (IMHO). Of course, this solution doesn't allow for much in the way of future enhancement.
use strict;
use warnings;
my @ids = qw(a b c d e f g h);
my $chosen_id = '';
my $last_id = '';
if (open (my $fh, 'recent')) {
$last_id = <$fh>;
close ($fh);
}
while (1) {
$chosen_id = @ids[ int( rand(@ids) ) ];
print "chosen: $chosen_id\n";
last if $chosen_id ne $last_id;
print "problem: $chosen_id is on the recent list, choose again\n";
}
# replace the file
open (my $fh, '>', 'recent')
or die "failed to open recent for write: $!\n";
print $fh $chosen_id;
close ($fh);
| [reply] [d/l] |