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

Here is a program for you guys to play around with. A somewhat disingeneous programming major thought he could use Perl to help him win the lottery. He created an array in which the index represented the lottery number and the value stored at that index represented the frequency of that number's occurence. He was doing this for the Texas Lottery where six numbers are chosen from 1 to 54 inclusive. He generated 10000 random numbers between 1 and 54 and stored the frequency distribution in his array. He then figured out how to sort the array in descending orderand displayed their frequencies in a simple table like this: 23 190, 31 189, 15 188, 3 187, 44 186, 8 185 The task is to write the source code to duplicate this output. Hint: imbedded FOR LOOPS

Replies are listed 'Best First'.
Re: Messing Around
by Fendaria (Beadle) on Feb 22, 2005 at 23:29 UTC

    Appoligies if this is out of place but this question really looks like a homework assignment.

    Fendaria
Re: Messing Around
by Mr. Muskrat (Canon) on Feb 23, 2005 at 03:06 UTC

    Your information is out of date. Currently, Lotto Texas is six numbers from 1 to 44. From 7/19/2000 through 5/3/2003, it was six numbers from 1 to 54. Prior to 7/19/2000, it was six numbers from 1 to 50.

    If I were to code up a Lotto script, I'd use WWW::Mechanize to pull the number frequency (and possibly all of the previous winning numbers) that the lottery commission provides.

Re: Messing Around
by phaylon (Curate) on Feb 22, 2005 at 23:06 UTC
    I don't get it, it's a three liner with a bit (or byte) combining.. Or has it to be readable? :D
    my @numbers; $numbers[ int(rand(54)) + 1 ]++ for 1 .. 10_000; print join ', ', ( map { "$_ ".($numbers[$_]||'0') } reverse sort { $n +umbers[ $a ] <=> $numbers[ $b ] } (1 .. 54) )[0..5];
    Update: I f'd it up with rand and put a 53 where a 54 should be. Thanks to ikegami for catching that.

    Ordinary morality is for ordinary people. -- Aleister Crowley

      No, it's a command-line one-liner.... perl -e 'srand;push(@c,0)foreach(0..53);foreach(1..1e4){@d=(); foreach(0..53){$e{$_}=1;}foreach(0..5){$i=int(rand(54));while (!$e{$i}){$i=int(rand(54));} push(@d,$i);$e{$i}=0;} foreach(@d){$c[$_]++}}foreach(sort{$c[$b]<=>$c[$a]}0..$#c) {print $_+1," ",$c[$_],", ";}'

      It also prevents duplicates per drawing. Explaining how it works and where they got it is left as an exercise to the student (as this smells a bit like homework)....

      Update 22 Feb 2005: Fixed small typos, added a few spaces into code.

      Update 22 Feb 2005: The code above appears to run in just under 1.0s, according to time(1), and weighs in around 267c total (256c for the code).

      int(rand(53)) + 1 gives a number from 1 to 53. Did you mean int(rand(54)) + 1?
        Yep, you got me :D I have a version here which doesn't pick numbers twice, but it's still running.. I guess this is not for production,

        Ordinary morality is for ordinary people. -- Aleister Crowley
Re: Messing Around
by ikegami (Patriarch) on Feb 22, 2005 at 23:00 UTC

    The code for your algorithm is easy:

    my @random_numbers; push(@random_numbers, int(rand(54)) + 1) foreach 1..10000; my %counts; $counts{$_}++ foreach @random_numbers; printf("%2d: %d\n", @$_) foreach sort { $a->[1] <=> $b[1] || $a->[0] <=> $b[0] } map { [ $_, $counts{$_} ] } keys(%counts);
    He generated 10000 random numbers between 1 and 54 and stored the frequency distribution in his array.

    Can the same number be picked twice? If not, your algo isn't representative. here's a fixedup version:

    # Picks 6 unique numbers uniformly between 1 and 54 inclusive. sub pick6 { my @nums; push(@nums, int(rand(54 - $_)) + 1) foreach 0..5; for my $i (1..5) { for my $j (0..$i-1) { $num[$i]++ if $num[$i] >= $num[$j]; } } return @nums; } my @random_numbers; push(@random_numbers, pick6()) foreach 1..10000; my %counts; $counts{$_}++ foreach @random_numbers; printf("%2d: %d\n", @$_) foreach sort { $a->[1] <=> $b[1] || $a->[0] <=> $b[0] } map { [ $_, $counts{$_} ] } keys(%counts);
    Hint: imbedded FOR LOOPS

    "embedded" is spelled with an "e", and "nested" is the proper term when talking about loops within loops.

Re: Messing Around
by sh1tn (Priest) on Feb 22, 2005 at 23:16 UTC
    If I understand the "problem":
    my @rand = 1..54; my %rand = map { $_=int rand($rand[$#rand])+1, $rand{$_}++ } 1..10000; print "$_\t$rand{$_}$/" for sort { $a <=> $b } keys %rand
    Update $rev{$rand{int rand(54)+1}++}++ for 1..10000


Re: Messing Around
by ambrus (Abbot) on Feb 23, 2005 at 10:16 UTC

    I'd do it with the statistics of numbers actually drewn in the lottery. Those stats are available from newspapers, or even from the internet. From these statistics of our national lottery, you get the following (The game is 5 numbers out of 1..90, and the statistics is from 2503 games.)

    Update: was broken link.

    To get the data, POST jatek=otos to www.szerencsejatek.hu/index.php?action=szamstat

Re: Messing Around
by borisz (Canon) on Feb 23, 2005 at 00:30 UTC
    And here is my try:
    my ( %c, @r ); $r[ int( rand(54) ) + 1 ]++ for ( 1 .. 10_000 ); printf "%2s $r[$_]\n", $_ for ( sort { $r[$b] <=> $r[$a] || $a <=> $b } map { my $x; 1 while ( $x = int( rand(54) ) + 1 and $c{$x}++ ); $x } ( 1 .. 6 ) );
    Boris