use List::Util qw(sum); my $total = sum values %$group; my $picked; for (keys %$group){ if (rand() < $group->{$_} / $total){ $picked = $_; last; } # update: I forgot this line: $total -= $group->{$_}; # without this line items later in the hash are chosen # too seldom, and you might chose none at all. Very bad. }