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

Hello.
Can someone give an exemple on how to write a program that print random number between 1 and 10 and does this.

1. I want the resultat to print 10 random number between 1 and 10.

2. If the first random number is 7. The second random number is between 1 and 10 but not number 7. The third random number is between 1 and 10 but not number 7 and not the same number like the second number.

3. And so on until every 10 random number has been printed.

For example for the resultat.
7
4
10
3
2
6
8
9
1
5

//Clyde
  • Comment on How to not print the same random number

Replies are listed 'Best First'.
Re: How to not print the same random number
by bart (Canon) on Mar 04, 2006 at 10:34 UTC
    A more efficient way to achieve what you want, is just to shuffle an array.

    To make the concept clear, let me compare to a deck of cards. How do you prevent from drawing the same card twice? By not putting the card back in the deck before you draw another one.

    You get the same result by simply shuffling the deck, and picking the next card, one by one.

    shuffle is a function you can find in List::Util. You use it like this:

    use List::Util 'shuffle'; my @shuffled_deck = shuffle 1 .. 10; local $\ = "\n"; foreach(@shuffled_deck) { print; }
    I get, for example, the following output:
    1
    2
    9
    8
    7
    10
    4
    5
    6
    3
    

    It'll be far more efficient than retrying until you get something you haven't seen before, especially near the end, when you've almost seen them all.

Re: How to not print the same random number
by borisz (Canon) on Mar 04, 2006 at 10:28 UTC
    Here is one way:
    perl -MList::Util=shuffle -e 'print "@{[shuffle(1..10)]}"'
    Boris
      While fine for small ranges, won't that be a hog on larger number ranges?
      update I understand that the poster is only looking for 1-10, just seemed the better way to teach. Opinions?

      -Lee
      "To be civilized is to deny one's nature."
        Yes sure, the array with all numbers is build and shuffled. On the other hand, hash solutions require more memory and more cpu power they build the same array but slower. A hash is a better choice, if you use only some number out of a large range. For really really much numbers a database is my best choice.
        Boris
        Not much of a hog. Storing the numbers already picked in a hash would be about as bad. (I'm not sure how many copies of the list the shuffle approach will end up having.)

        But anyway, if you go with what I understand to be your idea of repeatedly generating random numbers until you find one not yet in a hash, you'll end up taking a very very long time finding the last few numbers if the limit is, say, 1000000.

        The question becomes "are you going to use all the numbers in that range?" If so, you have to remember them all regardless of your approach. If no, then you could save memory by just tracking what you use... but this then becomes more processor-expensive.

Re: How to not print the same random number
by GrandFather (Saint) on Mar 04, 2006 at 11:05 UTC

    or you could just pull numbers out at random then throw them away:

    use strict; use warnings; my @numbers = 1..10; print splice (@numbers, rand (@numbers), 1), "\n" while @numbers;

    DWIM is Perl's answer to Gödel
Re: How to not print the same random number
by shotgunefx (Parson) on Mar 04, 2006 at 09:21 UTC
    Sounds like homework. I'll give you a hint. When you want to keep track of things you've seen, a hash is usually what you want.

    You'll have a lot better luck getting help if you actually give it a go and post what you've got.

    -Lee
    "To be civilized is to deny one's nature."
Re: How to not print the same random number
by GrandFather (Saint) on Mar 04, 2006 at 11:02 UTC

    This may give you what you want:

    use strict; use warnings; print join"\n",grep$_,map{our%s;my$n=1+int rand(10);$s{$n}++?0:$n}1..1 +00;

    DWIM is Perl's answer to Gödel
      I like the "may" part. Did you calculate the actual odds?

        Statistics is not my strong suit. I ran a test version a few times and noticed that about 23-25 itterations sufficed often enough and guessed that 100 would seldom dissapoint. Glad you noticed the "may". :)


        DWIM is Perl's answer to Gödel
Re: How to not print the same random number
by spiritway (Vicar) on Mar 04, 2006 at 11:46 UTC

    If you're excluding numbers, it's not random. For example, if you've already chosen 9 numbers, the tenth is completely determined. FWIW.

Re: How to not print the same random number
by TedPride (Priest) on Mar 04, 2006 at 15:12 UTC
    The following should achieve pretty random results within the constraints you asked for - 10 unique numbers from 1-10 sorted randomly.
    @arr = 1..10; randomize(\@arr); print "@arr"; sub randomize { my ($p, $size, $swap, $key); $p = $_[0]; $size = $#$p; for (0..($size-1)) { $swap = int rand($size - $_ + 1) + $_; $key = $p->[$_]; $p->[$_] = $p->[$swap]; $p->[$swap] = $key; } }

      You can eliminate the manifest temporary by:

      ($p->[$_], $p->[$swap]) = ($p->[$swap], $p->[$_]);

      Note though that it is slower:

      use strict; use warnings; use Benchmark qw(cmpthese); my @arr = 1..2; cmpthese (-1, { temp => sub {my $temp = $arr[0]; $arr[0] = $arr[1]; $arr[1 +] = $temp;}, swap => sub {($arr[0], $arr[1]) = ($arr[1], $arr[0]);}, } ); Rate swap temp swap 1381331/s -- -43% temp 2425611/s 76% --

      DWIM is Perl's answer to Gödel
    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: How to not print the same random number
by TedPride (Priest) on Mar 04, 2006 at 17:42 UTC
    ## Assign the numbers 1-10 to array @arr @arr = 1..10; ## Pass @arr by reference to function randomize() randomize(\@arr); ## When used in this context, the array prints ## with space delimiters between items print "@arr"; sub randomize { ## Declare variables inside the scope of ## this function my ($p, $size, $swap, $key); ## Assign the array reference passed to ## the function to $p $p = $_[0]; ## Assign the length of the array pointed ## to by $p to $size. This is the number ## of items in the array - 1 $size = $#$p; ## Randomize all items up to the next to ## last item. The last item is randomized ## already if the other items are. for (0..($size-1)) { ## Pick a random item from current ## position to end $swap = int rand($size - $_ + 1) + $_; ## Swap item with current position $key = $p->[$_]; $p->[$_] = $p->[$swap]; $p->[$swap] = $key; } }
    You should probably look up $_ and @_ and read up on references, it will help you understand this a bit.
Re: How to not print the same random number
by cognizant (Pilgrim) on Mar 04, 2006 at 10:39 UTC
    Try this
    use Data::Random qw(:all); my @random_chars = rand_chars( set => 'numeric', min => 10, max => 10 +); foreach (@random_chars) {print "$_\n";}
    --C