in reply to Re: Re: Choosing a random product from an Array
in thread Choosing a random product from an Array

I think that's a very good point. Having duplicate members in the initial listing is a perfectly valid way to assign different weights to different products. It stands to reason that my, admittedly, heavy-handed approach could be made more elegant. In fact, you really only need to store the invalid ones, and this can be flipped around in a jiffy.
use warnings; use strict; my @first = qw( 1 3 5 7 9 11 13 15 17 19 21 23 ); my @second = qw( 1 5 9 13 17 21 ); sub random_from { my ($first, $second) = @_; my %invalid = (map { $_ => 1 } @$second); my $return; do { # Choose a random key from the combined listing $return = $first->[rand(@$first)]; } while ($invalid{$return}); return $return; } print "Selection: ",random_from(\@first, \@second),$/;
Update: I'd just thought to clarify why the hash was called %valid. While it's true that it contains valid and invalid members, the purpose of the hash is to store the valid status of the entry. Obscure, perhaps, oblique, maybe, but functional.

Replies are listed 'Best First'.
Re: Re^3: Choosing a random product from an Array
by sauoq (Abbot) on Nov 17, 2002 at 02:47 UTC

    After making those changes, you're left with basically the same solution I proposed in my first reply in this thread.

    I liked your idea of combining the arrays initially because, if you do it right, it allows the choosing of a random element to be an O(1) operation instead of an iterative one which is dependent on the distribution of valid and invalid elements. You can achieve this and still permit duplicate members with some additional setup.

    my @one = qw( 1 3 5 7 9 11 13 13 15 15 17 19 21 23 ); my @two = qw( 1 5 9 13 17 21 ); my %valid; $valid{$_}++ for @one; @valid{@two} = (0) x @two; @choices = map { ($_) x $valid{$_} } keys %valid; sub randelt { $choices[rand @choices] }
    -sauoq
    "My two cents aren't worth a dime.";