I want to be able to randomly select from this set with three different biases: favoring the popular, impartial, and favoring the unpopular.{ alligator => 100, bear => 90, cat => 80, ... jellyfish => 10 } total_votes = 550
The impartial case is simple; choose the Nth item where 0 <= N <= 9.
To favor the popular, you choose a random number N from 0 to 549, then traverse the set of animals, subtracting each one's popularity from N until N goes negative, and that's the animal you choose.
But I can't figure out how to favor those with the least popularity. (Admittedly, this is more of an algorithm question than a Perl question, and I'll gladly take it to a different forum if it's inappropriate for PM.)
Here's my demo code;
#!/usr/bin/env perl use 5.010; use warnings; use strict; # Initialize %votes: map animals to their number of votes. my @animals = qw/alligator bear cat dog elephant fox giraffe hippo iguana jell +yfish/; my $votes = 100; # start with 100 votes for first word my $decr = int( $votes / (@animals) ); # evenly decrease # of votes my $sum = 0; # grand total of votes for all words my %votes = map {my $n = $votes; $sum += $n; $votes -= $decr; ( $_, $n )} @animals; # Display animals and votes print '===> '; printf "%s:%3d ", $_, $votes{$_} for sort keys %votes; print " Total votes=$sum"; # Get random selections my %popular; my %impartial; my %unpopular; for ( 1 .. $sum ) { $popular{ popular() }++; # should tend toward the popular $impartial{ impartial() }++; # should be equally distributed $unpopular{ unpopular() }++; # should tend toward the unpopular } # Display distribution of votes from each method print "\nPOP: "; printf "%s:%3d ", $_, $popular{$_}//0 for sort keys %votes; print "\nIMP: "; printf "%s:%3d ", $_, $impartial{$_}//0 for sort keys %votes; print "\nUNP: "; printf "%s:%3d ", $_, $unpopular{$_}//0 for sort keys %votes; say ''; # Method 1: choose randomly with preference for higher vote-getters sub popular { my $rand = int( rand $sum ); for my $key ( # sort { ($votes{$b} <=> $votes{$a}) } #unnecessary keys %votes ) { return $key if ( $rand -= $votes{$key} ) <= 0; } die 'popular bug'; } # Method 2: choose randomly without regard for popularity sub impartial { return ( keys %votes )[ rand keys %votes ]; } # Method 3: choose randomly with preference for lower vote-getters sub unpopular { return '?'; }
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |