random numbers

Discussion in 'Perl Misc' started by Mei, Jun 6, 2005.

  1. Mei

    Mei Guest

    Hi,



    I want to generate 6 random numbers from 1 to 10.

    The 6 numbers must not the same.

    These numbers must match to the number of an array.

    I like to know how many iterations to get the match.



    I am having troubles with the do-until loop. Could someone point out the
    problem for me?



    #!/usr/bin/perl -w

    # generate 6 random numbers (1~10) that match exactly to the @ticket

    # count the number of loops



    use strict;

    srand(time||$$);



    my @ticket = sort (2, 3, 5, 7, 8, 10);

    my @all_number = ();

    my @new_number = ();

    my $count = 0;



    # generate 10 numbers

    for (my $i = 0; $i < 10; $i++) {

    my $number = $i + 1;

    push (@all_number, $number)

    }



    do {

    #reset @new_number to the empty array each time through the loop.

    @new_number = ();



    #get 6 random numbers

    for (my $i = 0; $i < 6; $i++) {

    my $position = randomposition (@all_number);

    # Pick a random number from @all_number

    my $number = splice (@all_number, $position, 1);

    push (@new_number, $number);

    }

    @new_number = sort (@new_number);

    print "@new_number\n";

    $count++;



    } until (($new_number[0] eq "$ticket[0]") && ($new_number[1] eq
    "$ticket[1]")

    && ($new_number[2] eq "$ticket[2]") && ($new_number[3] eq
    "$ticket[3]")

    && ($new_number[4] eq "$ticket[4]") && ($new_number[5] eq
    "$ticket[5]"));



    print $count, "\n";



    ##########################################################

    sub randomposition {

    my(@all_number) = @_;

    # This expression returns a random number

    return int(rand(scalar(@all_number)));

    }
    Mei, Jun 6, 2005
    #1
    1. Advertising

  2. "Mei" <> wrote in news:d81eva$h2i$:

    [ what's up with the extra line-feeds? ]

    > I want to generate 6 random numbers from 1 to 10.
    > The 6 numbers must not the same.



    > These numbers must match to the number of an array.
    > I like to know how many iterations to get the match.


    I am not sure what you mean by this.

    > #!/usr/bin/perl
    >
    > use strict;


    use warnings;

    is better because it allows you to turn warnings for selected lexical
    scopes.

    > srand(time||$$);


    Why? Note that, unless your Perl is severely broken, this is equivalent
    to srand(time). From perldoc -f srand:

    In versions of Perl prior to 5.004 the default seed was just the
    current "time". This isn't a particularly good seed, so many old
    programs supply their own seed value (often "time ^ $$" or "time
    ^ ($$ + ($$ << 15))"), but that isn't necessary any more.

    > my @ticket = sort (2, 3, 5, 7, 8, 10);


    > my @all_number = ();
    > my @new_number = ();
    > my $count = 0;


    Declare variables in the smallest applicable scope.

    > # generate 10 numbers
    >
    > for (my $i = 0; $i < 10; $i++) {
    >
    > my $number = $i + 1;
    >
    > push (@all_number, $number)
    >
    > }


    So, instead of this for loop, use:

    my @all_number = (1 .. 10);

    > do {
    > #reset @new_number to the empty array each time through the loop.
    > @new_number = ();


    my @new_number();
    >
    > #get 6 random numbers
    > for (my $i = 0; $i < 6; $i++) {
    > my $position = randomposition (@all_number);
    > # Pick a random number from @all_number
    > my $number = splice (@all_number, $position, 1);
    > push (@new_number, $number);
    > }


    This is realy convoluted (and therefore confuses me still further as to
    what you are trying to do).

    for (1 .. 6) {
    push @new_number, $all_number[ int(rand( scalar @all_number )) ];
    }

    It seems to me like what you are really doing is to check how long it
    would take for you to generate the sequence (0, 1, 2, 3, 4, 5) by
    randomly selecting (with replacement) from the set {0, 1, 2, 3, 4, 5}.

    Here is one way of doing it:

    # !/usr/bin/perl

    use strict;
    use warnings;

    my @ticket = sort {$a <=> $b } (2, 3, 5, 7, 8, 10);
    my $ticket = "@ticket";

    my $count = 0;

    while ( 1 ) {
    ++$count;

    my @new;
    for (1 .. 6) {
    push @new, $ticket[ int(rand( scalar @ticket )) ];
    }

    @new = sort {$a <=> $b } @new;
    my $new = "@new";

    print "$new\tvs\t$ticket\n";

    last if $new eq $ticket;
    }

    print "Count = $count\n";

    __END__

    Please do read the posting guidelines for this group tolearn how you can
    help yourself and help others help you.

    Sinan

    --
    A. Sinan Unur <>
    (reverse each component and remove .invalid for email address)

    comp.lang.perl.misc guidelines on the WWW:
    http://mail.augustmail.com/~tadmc/clpmisc/clpmisc_guidelines.html
    A. Sinan Unur, Jun 6, 2005
    #2
    1. Advertising

  3. * Mei schrieb:
    >
    > I want to generate 6 random numbers from 1 to 10.
    > The 6 numbers must not the same.
    > These numbers must match to the number of an array.
    > I like to know how many iterations to get the match.
    >
    > I am having troubles with the do-until loop. Could someone point out the
    > problem for me?
    >
    > #!/usr/bin/perl -w
    > # generate 6 random numbers (1~10) that match exactly to the @ticket
    > # count the number of loops
    > use strict;
    > srand(time||$$);


    You don't have to call srand() explicitly. It is called implicitly at
    the first use of rand() since your Perl isn't very old. Have a look at
    `perldoc -f srand` for details.

    >
    > my @ticket = sort (2, 3, 5, 7, 8, 10);


    Your numbers are already sorted numerically. After calling sort() on
    them, your list looks like (10,2,3,5,7,8). This doesn't matter since you
    sort your numbers in the same order later -- but be aware of this.

    >
    > my @all_number = ();
    > my @new_number = ();
    > my $count = 0;
    >
    > # generate 10 numbers
    > for (my $i = 0; $i < 10; $i++) {
    > my $number = $i + 1;
    > push (@all_number, $number)
    > }


    To get a list with all numbers from 1 to 10, please use

    my @all_number = 1 .. 10;

    >
    > do {
    > #reset @new_number to the empty array each time through the loop.
    > @new_number = ();
    >
    > #get 6 random numbers
    > for (my $i = 0; $i < 6; $i++) {
    > my $position = randomposition (@all_number);
    > # Pick a random number from @all_number
    > my $number = splice (@all_number, $position, 1);
    > push (@new_number, $number);
    > }


    Consider to use map instead of this for loop. And IMHO is splice() too
    much pverhead for this -- you could access each array element directly
    since you know its position. Try to use one of (I don't know which is
    more readable to you):

    @new_number = map { $all_number[ rand @all_number ] } 0 .. 5;
    @new_number = @all_number[ map { rand @all_number } 0 .. 5 ];

    >
    > @new_number = sort (@new_number);


    This is what I've meant above. This sort() doesn't sort your numbers
    numerically too. But it's just important to sort the numbers in the same
    order as above (and this is what you're doing). If -- and only if -- you
    left out the sort statement above, you should sort numerically here, I
    think your code gets more clarity then.

    @new_number = sort { $a <=> $b } @new_number;

    >
    > print "@new_number\n";
    > $count++;
    > } until (($new_number[0] eq "$ticket[0]") && ($new_number[1] eq "$ticket[1]")
    > && ($new_number[2] eq "$ticket[2]") && ($new_number[3] eq "$ticket[3]")
    > && ($new_number[4] eq "$ticket[4]") && ($new_number[5] eq "$ticket[5]"));


    To compare numbers there is the == operator, eq is for comparing strings
    only. I haven't checked it out yet, but AFAIK the numerical ones should
    be a little bit faster. And well, it's not funny to read such repeated
    code fragments. Perhaps you could use grep() instead.

    } until ! grep { $ticket[$_] != $new[$_] } 0 .. 5;

    >
    > print $count, "\n";
    >
    > ##########################################################
    >
    > sub randomposition {
    > my(@all_number) = @_;
    > return int(rand(scalar(@all_number)));
    > }


    This sub could be shortened to

    sub randomposition { int rand @_ }

    and since writing "int rand @_" is shorter than "randomposition" you
    could omit to declare a sub for such a triviality.

    All in one, I would write your script as something like:


    #!/usr/bin/perl -w
    use strict;

    my @ticket = sort 2, 3, 5, 7, 8, 10;
    my @all = 1 .. 10;
    my @new;
    my $count = 0;

    do {
    @new = sort @all[ map { rand @all } 0 .. 5 ];
    $count++;
    } until ! grep { $ticket[$_] != $new[$_] } 0 .. 5;

    print $count;
    __END__


    regards,
    fabian
    Fabian Pilkowski, Jun 6, 2005
    #3
  4. Mei

    Guest

    "Mei" <> wrote:
    > Hi,
    >
    > I want to generate 6 random numbers from 1 to 10.
    >
    > The 6 numbers must not the same.


    my %h;

    $h{int(rand(10)+1)} =1 while (6 > keys %h) ;

    # the keys of %h are now 6 distinct random numbers between 1 and 10.

    (I couldn't figure out how your code pertained to what you said you wanted
    above, so I ignored it)

    Xho

    --
    -------------------- http://NewsReader.Com/ --------------------
    Usenet Newsgroup Service $9.95/Month 30GB
    , Jun 6, 2005
    #4
  5. Mei

    Thomas Kratz Guest

    Fabian Pilkowski wrote:
    > * Mei schrieb:
    >
    >>I want to generate 6 random numbers from 1 to 10.
    >>The 6 numbers must not the same.
    >>These numbers must match to the number of an array.
    >>I like to know how many iterations to get the match.


    > All in one, I would write your script as something like:
    >
    >
    > #!/usr/bin/perl -w
    > use strict;
    >
    > my @ticket = sort 2, 3, 5, 7, 8, 10;
    > my @all = 1 .. 10;
    > my @new;
    > my $count = 0;
    >
    > do {
    > @new = sort @all[ map { rand @all } 0 .. 5 ];
    > $count++;
    > } until ! grep { $ticket[$_] != $new[$_] } 0 .. 5;
    >
    > print $count;
    > __END__


    or if only the number of iterations is of interest:

    use strict;
    use warnings;

    my %ticket = map { $_ => 1 } qw/2 3 5 7 8 10/;
    my $count = 0;
    $count++ && delete $ticket{int(rand(10))+1} while keys %ticket;
    print $count;

    Thomas

    --
    $/=$,,$_=<DATA>,s,(.*),$1,see;__END__
    s,^(.*\043),,mg,@_=map{[split'']}split;{#>J~.>_an~>>e~......>r~
    $_=$_[$%][$"];y,<~>^,-++-,?{$/=--$|?'"':#..u.t.^.o.P.r.>ha~.e..
    '%',s,(.),\$$/$1=1,,$;=$_}:/\w/?{y,_, ,,#..>s^~ht<._..._..c....
    print}:y,.,,||last,,,,,,$_=$;;eval,redo}#.....>.e.r^.>l^..>k^.-
    Thomas Kratz, Jun 6, 2005
    #5
  6. Mei

    Mei Guest

    Hi,



    --Thanks all. The reason that I did not use 1..10 is because the six numbers
    must be different.

    --Once I take off the do-until loop, you will see the result like: ¡§1 3 4 6
    8 10 vs 2 3 5 7 8 10¡¨. So far, this works.

    -- But as you pointed out, I want to see how long would it take for me to
    generate the sequence (2, 3, 5, 7, 8, 10). So far, I am still having
    troubles.



    ###### modified from the previous script #####

    #!/usr/bin/perl -w

    # generate 6 random numbers (1~10) that match exactly to the @ticket

    # count the number of loops

    use strict;

    my @ticket = sort {$a <=> $b} (2, 3, 5, 7, 8, 10);

    my $ticket = "@ticket";

    my @all_number = ();

    my @new_number = ();

    my $count = 0;



    # generate 10 numbers

    for (my $i = 0; $i < 10; $i++) {

    my $number = $i + 1;

    push (@all_number, $number)

    }



    for (my $i = 0; $i < 6; $i++) {

    my $position = int(rand(scalar(@all_number)));

    # Pick a random number from @all_number

    my $number = splice (@all_number, $position, 1);

    push (@new_number, $number);

    }

    @new_number = sort {$a <=> $b} (@new_number);

    my $new_number = "@new_number";

    print "$new_number\tvs\t$ticket\n";

    $count++;
    Mei, Jun 6, 2005
    #6
  7. * Mei schrieb:
    >
    > --Thanks all. The reason that I did not use 1..10 is because the six numbers
    > must be different.


    The "1..10" has almost nothing to do with your 6 numbers. "1..10" is
    generating ten numbers, not six.

    >
    > --Once I take off the do-until loop, you will see the result like: ¡§1 3 4 6
    > 8 10 vs 2 3 5 7 8 10¡¨. So far, this works.
    >
    > -- But as you pointed out, I want to see how long would it take for me to
    > generate the sequence (2, 3, 5, 7, 8, 10). So far, I am still having
    > troubles.


    You don't mention which kind of troubles you have.

    >
    > ###### modified from the previous script #####
    >
    > #!/usr/bin/perl -w
    > # generate 6 random numbers (1~10) that match exactly to the @ticket
    > # count the number of loops
    > use strict;
    >
    > my @ticket = sort {$a <=> $b} (2, 3, 5, 7, 8, 10);
    > my $ticket = "@ticket";
    > my @all_number = ();
    > my @new_number = ();
    > my $count = 0;
    >
    > # generate 10 numbers
    > for (my $i = 0; $i < 10; $i++) {
    > my $number = $i + 1;
    > push (@all_number, $number)
    > }


    This for loop is generating the numbers from 1 to 10 and saves them in
    the array @all_number -- not more, not less. This has absolutely nothing
    to do with your six different numbers you want to get afterwards. And as
    Sinan has pointed out you could replace this with

    @all_number = 1 .. 10;

    This is absolutely equivalent, but shorter -- and better to read.

    >
    > for (my $i = 0; $i < 6; $i++) {
    > my $position = int(rand(scalar(@all_number)));
    > # Pick a random number from @all_number
    > my $number = splice (@all_number, $position, 1);
    > push (@new_number, $number);
    > }


    This for loop *calculates* your six random numbers. First, it gets a
    random position in the array. With splice() you ask for the specified
    element in your array to push it into the array @new_number. This could
    be simplified to

    for ( 1 .. 6 ) {
    my $pos = int rand @all_number; # no scalar() needed
    my $number = $all_number[ $pos ]; # no splice() needed
    push @new_number, $number;
    }

    You could write this all in one, without saving some values in $pos and
    $number. That is, what Sinan has written:

    for ( 1 .. 6 ) {
    push @new_number, $all_number[ rand @all_number ];
    }

    Sure, you could use map() instead of a for loop. That is, what I've done
    in my posting:

    @new_numbers = map { $all_number[ rand @all_number ] } 1 .. 6;

    Remember that this are just improvements to the code you've posted. I
    think, your problem is to get six *different* numbers. Neither your code
    nor our improvements will do this. But Xho has told you how this could
    be done with a hash:

    my %hash;
    $hash{ int rand @all_number } = 1 while keys %hash < 6;
    @new_numbers = @all_number[ keys %hash ];

    Another solution is to use List::Util's shuffle algorithm and cut off a
    subarray of six elements. This could be more readable, especially if
    you're not so familiar with hashes.

    use List::Util qw( shuffle );
    @new_numbers = ( shuffle @all_number )[ 0 .. 5 ];

    Please, try to run the following script:


    #!/usr/bin/perl -w
    use strict;
    use List::Util qw( shuffle );

    my @ticket = sort 2, 3, 5, 7, 8, 10;
    my @all = 1 .. 10;
    my $count = 0;

    while ( ++$count ) {
    # get six different elements from @all
    my @new = sort +( shuffle @all )[ 0 .. 5 ];

    # print out for debugging
    print "@ticket vs @new\n";

    # stop if @ticket and @new are equal
    last if "@ticket" eq "@new";
    }

    print $count;
    __END__


    regards,
    fabian
    Fabian Pilkowski, Jun 7, 2005
    #7
  8. Mei

    Don Salad Guest

    > I want to generate 6 random numbers from 1 to 10.
    >
    > The 6 numbers must not the same.
    >
    > These numbers must match to the number of an array.
    >
    > I like to know how many iterations to get the match.


    That should be OK, but it's VERY IMPORTANT not to generate too many
    random numbers, or you could end up with the same problem as
    calculating pi: you may inadvertently generate copyright
    infringements, child pr0n, death threats, etc.

    Thanks,
    Don
    Don Salad, Jun 7, 2005
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. globalrev
    Replies:
    4
    Views:
    734
    Gabriel Genellina
    Apr 20, 2008
  2. Alex Untitled
    Replies:
    11
    Views:
    643
    Giampiero Zanchi
    Nov 16, 2009
  3. PerlFAQ Server

    FAQ 4.10 Why aren't my random numbers random?

    PerlFAQ Server, Feb 12, 2011, in forum: Perl Misc
    Replies:
    0
    Views:
    209
    PerlFAQ Server
    Feb 12, 2011
  4. PerlFAQ Server

    FAQ 4.10 Why aren't my random numbers random?

    PerlFAQ Server, Apr 27, 2011, in forum: Perl Misc
    Replies:
    0
    Views:
    235
    PerlFAQ Server
    Apr 27, 2011
  5. VK
    Replies:
    15
    Views:
    1,099
    Dr J R Stockton
    May 2, 2010
Loading...

Share This Page