Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Difficulty in randomization

by Anonymous Monk
on Mar 04, 2012 at 21:08 UTC ( [id://957812]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks!
I have the following task:
I have an empty array of length say 600 and a number, say 10.
I want to create 1000 such arrays (and subsequently strings using 'join') by randomly assigning 10 positions in each array to be 'X' while the remaining 590 will be '-'.
I did the following:
@array=(); for($i=1; $i<=10; $i++) { $random_number = rand(600); if($array[$random_number] ne 'X' ) {$array[$random_number]='X';} else {$random_number = rand(600);} } for ($j=0; $j<600; $j++) { if($array[$j] ne 'X') {$array[$j]='-'} } $joined_new_string=join('', @array);

My problem is that I must be doing something wrong, because not all 600 strings produced have 10 positions with 'X' each. And I am suspecting that in my first for loop, I must somehow "remove" the position that is assigned a 'X' in each randomization, because if, for example, in the first run, I assign the 'X' in position 55, the next rand(600) might also give 55 and I will miss one assignment.
How can this be solved?

Replies are listed 'Best First'.
Re: Difficulty in randomization
by jwkrahn (Abbot) on Mar 04, 2012 at 21:52 UTC
    $ perl -le' use List::Util q/shuffle/; my $string_length = 600; my $x_count = 10; my $joined_new_string = q/-/ x $string_length; my @positions = ( shuffle 0 .. $string_length - 1 )[ 0 .. $x_count - 1 + ]; substr $joined_new_string, $_, 1, q/X/ for @positions; print $joined_new_string; ' -----------------------------X---------------------------------------- +--------------------------------------------------------------------X +--------------------------------------------------------------------- +----X----X-------X-------------------------------------X------------- +---------------------------------------------X-X--------------------- +--------------------------------------------------------------------- +------------------------------------------------------------X-------- +--------------------------------------------------------------------- +------------------------X----------------------
Re: Difficulty in randomization
by kejohm (Hermit) on Mar 04, 2012 at 21:41 UTC

    Instead of using if in your loop, you can use a do {...} while loop, eg:

    my @array; for ( 1 .. 10 ) { my $random_number; do { $random_number = rand 600; } while $array[$random_number] eq 'X'; $array[$random_number] = 'X'; }

    Here we generate a random number inside the loop and check whether the element at that position has been assigned 'X'. If it is, we try again. Otherwise, we assign 'X' to the selected element.

Re: Difficulty in randomization
by GrandFather (Saint) on Mar 05, 2012 at 00:26 UTC

    Turning the code into Perl rather than C and fixing for missing X's:

    use warnings; use strict; my $len = 600; my $str = '-' x $len; for (1 .. 10) { my $index = rand($len); redo if 'X' eq substr $str, $index, 1; substr $str, $index, 1, 'X'; } my $xCount = $str =~ tr/X/X/; print "$xCount: >$str<\n";

    Prints:

    True laziness is hard work
Re: Difficulty in randomization
by tobyink (Canon) on Mar 04, 2012 at 21:57 UTC
    use 5.010; use strict; # A few definitions... use constant { ITERATIONS => 20, # number of random strings to generate LENGTH => 72, # length of each string X_COUNT => 4, # number of X characters in each string }; # We need a uniq() function. List::MoreUtils provides a fast XS based # one, but if they don't have it installed, fall back to a pure Perl # alternative. BEGIN { *uniq = eval { require List::MoreUtils; 1 } ? \&List::MoreUtils::uniq : sub (@) { my %seen = (); grep { not $seen{$_}++ } @_ }; } # We want to generate more than one random string. foreach my $iter (1 .. ITERATIONS) { # Make a pool of random numbers. uniq ensures no duplicates, # but means that we might end up with fewer than we need, # hence a loop to top up the pool if it's below the number # we need. my @positions; while (@positions < X_COUNT) { push @positions, map { int rand LENGTH } 0 .. X_COUNT; @positions = uniq @positions; } # Take just the first X_COUNT items from our pool, then # map it into a hash structure. my %exes = map { $_ => 1 } @positions[0 .. X_COUNT-1]; # Create our array of length LENGTH. Indexes found in the # %exes hash get an "X"; other indexes get a hyphen. my @array = map { $exes{$_} ? 'X' : '-' } 1 .. LENGTH; # Print out the array as a string. say join q{}, @array; }
Re: Difficulty in randomization
by JavaFan (Canon) on Mar 04, 2012 at 23:00 UTC
    Considering that 10 is much smaller than 600, I'd do:
    my @array = ('-') x 600; foreach (1 .. 10) { my $i = int rand 600; redo if $array[$i] eq 'X'; $array[$i] = 'X'; } my $joined_string = join "", @array;
    In theory, this may run "for ever", but in practice it will run fast enough.

      Same thing without the array:

      my $joined_string = '-' x 600; foreach ( 1 .. 10 ) { my $i = int rand 600; redo if 'X' eq substr $joined_string, $i, 1; substr $joined_string, $i, 1, 'X'; }
Re: Difficulty in randomization
by kcott (Archbishop) on Mar 05, 2012 at 10:41 UTC

    Here's a solution using an array slice.

    #!/usr/bin/env perl use 5.010; use strict; use warnings; use List::Util qw{shuffle}; my $array_elements = 60; # originally 600 my $random_elements = 3; # originally 10 my $no_of_arrays = 10; # originally 1000 my $norm_char = q{-}; my $rand_char = q{X}; my @all_strings = (); for (1 .. $no_of_arrays) { my @tmp_array = ($norm_char) x $array_elements; @tmp_array[(shuffle 0 .. $array_elements - 1)[0 .. $random_element +s - 1]] = ($rand_char) x $random_elements; push @all_strings => join q{} => @tmp_array; } map { say } @all_strings;

    -- Ken

Re: Difficulty in randomization
by Not_a_Number (Prior) on Mar 05, 2012 at 19:35 UTC

    Short version for Monks who don't like typing:

    use List::Util qw/ shuffle /; my @strings = map { join '', shuffle( ('X') x 10, ('-') x 590 ) } 1 .. + 1000;

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://957812]
Approved by davido
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (3)
As of 2024-04-25 06:48 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found