{ my $funcs; sub weighted_rand { my @weight=@_; my $key=join(',', @weight); return &{$funcs->{$key}} if($funcs->{$key}); # use existing function my $sum; map { $sum += $_ } @weight; my $scale=100/$sum; my @outcome; my $outcome=0; foreach my $w ( @weight ) { my $cnt=sprintf "%.0f", $w*$scale; # get a rounded number of slots push @outcome, (split '', $outcome x $cnt); $outcome++; } my $outcount=@outcome; # if the rounding gets us 99 or 101 this will adjust the function $funcs->{$key} = sub { $outcome[rand($outcount)] }; return &{$funcs->{$key}}; } }