Do you have a question? Post it now! No Registration Necessary. Now with pictures!
- Subject
- Posted on
- random numbers
- 06-07-2005
posted on
June 7, 2005, 1:18 am
June 7, 2005, 1:18 am
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)));
}
Re: random numbers
[ what's up with the extra line-feeds? ]
I am not sure what you mean by this.
use warnings;
is better because it allows you to turn warnings for selected lexical
scopes.
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.
Declare variables in the smallest applicable scope.
So, instead of this for loop, use:
my @all_number = (1 .. 10);
my @new_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
--
(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
Re: random numbers
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++;
Re: random numbers
* Mei schrieb:
The "1..10" has almost nothing to do with your 6 numbers. "1..10" is
generating ten numbers, not six.
You don't mention which kind of troubles you have.
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.
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
Re: random numbers
my %h;
$h =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
Re: random numbers
* Mei schrieb:
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.
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.
To get a list with all numbers from 1 to 10, please use
my @all_number = 1 .. 10;
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 ];
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;
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;
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
Re: random numbers
Fabian Pilkowski wrote:
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 while keys %ticket;
print $count;
Thomas
--
$/=$,,$_=<DATA>,s,(.*),$1,see;__END__
s,^(.*3),,mg,@_=mapsplit;{#>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^.-
Site Timeline
- » FAQ 1.3 Which version of Perl should I use?
- — Next thread in » PERL Discussions
- » eval not work
- — Previous thread in » PERL Discussions
- » s suffix question
- — Newest thread in » PERL Discussions
- » Dell Battery Slice LED codes
- — The site's Newest Thread. Posted in » Laptop Computers Forum