I have a hash that maps a set of things to their "popularity". In this example, there are ten animals, each of which has received a certain number of votes.
{ alligator => 100, bear => 90, cat => 80, ... jellyfish => 10 } total_votes = 550
I want to be able to randomly select from this set with three different biases: favoring the popular, impartial, and favoring the unpopular.

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 '?'; }

In reply to Randomly choosing from a set of alternatives with varying popularity by ibm1620

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.