I developed a formula to randomly pick N items based on their weights (for what you ask for, N == 1) that I could use on an array and even in SQL, that you can find here. The basic idea is to sort the items based on a calculated random value from the expression
-log(1 - rand)/$weight
where $weight is the weight factor for the current item. You can find the rationale behind the formula in that post.

For one item, you can reduce the code to picking the item where this expression has the lowest value. There's no need to actually sort them all.

Here is code for the reduced problem:

my @matrix = ( [a => 0.1], [b => 0.5], [c => 0.4] ); my $chosen = pick(@matrix); sub pick { my($choice, $threshold); foreach(@_) { my $rand = -log(1 - rand)/$_->[1]; if(not defined $threshold or $rand < $threshold) { $choice = $_->[0]; $threshold = $rand; } } return $choice; }
For better randomness of a huge number of draws, it's better to pick a random number generator that has a higher number of bits (and a larger cycle) than the default one (only 15 bits on ActivePerl/Windows!), for example Math::Random::MT which can be used as a plug in replacement if you import (and override) rand.
use Math::Random::MT qw(rand);

To demonstrate that it works as advertised, here are the results of a test run of 100_000 draws:

my %picked; for(1 .. 1E5) { $picked{pick(@matrix)}++; } use Data::Dumper; print Dumper \%picked;
Output:
$VAR1 = { 'c' => 40200, 'a' => 10042, 'b' => 49758 };
which looks very close to the desired distribution, to me.

p.s. If there can be any items with weight 0, thus, that should never be picked, you will have to skip them at the top of the loop, because otherwise, the expression will barf (division by zero).


In reply to Re: How do I get a random index with weighting? by bart
in thread How do I get a random index with weighting? by m_al

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.