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

So I'm discussing Lottery numbers with my significant other, who says "I don't understand why picking seven numbers costs so much more than six numbers".

So I draw a little diagram like this

#234567 1#34567 12#4567 123#567 1234#67 12345#7 123456#
to show that when we pick seven numbers, that includes seven different possible combinations of the six numbers they draw.

"I see", says my significant other, "so seven numbers is like playing seven games, so eight numbers is like having eight games?"

Aha, no, I say, because with eight numbers, you have ... hold on sweetheart, let me write a script for this.

So I write this:

@numbers = (1..8); for ( 0 .. 7 ) { @outer = @numbers; $outer[$_] = '#'; for ( 0 .. 7 ) { @inner = @outer; unless ( $inner[$_] eq '#' ) { $inner[$_] = '#'; print @inner, $/; $count++; } } } print "$count possible winning combinations\n";
which dutifully prints out
##345678 #2#45678 #23#5678 etc
and shows that a System 8 entry is the same as 56 games.

OK, says the longsuffering Significant Other, "...and with nine numbers?"

At which point I realise my code isn't very smart.

What would other monks write if they wanted to perform this exercise on an array with an arbitrary number of items? And how short could it be?



($_='kkvvttuubbooppuuiiffssqqffssmmiibbddllffss') =~y~b-v~a-z~s; print

Replies are listed 'Best First'.
Re: Lottery combinations golf
by tilly (Archbishop) on Oct 12, 2003 at 06:14 UTC
    See Combinatorics for some solutions to a closely related problem.
Re: Lottery combinations golf
by atcroft (Abbot) on Oct 12, 2003 at 07:56 UTC

    Well, I had thought that perhaps Algorithm::Permute might be the answer, but according to its documentation, so far it only deals with n arrangements of n items. Given that, and the amount of time it can take for even a small set of matches, I tossed together the following, based fairly closely on its docs. I *DO NOT* recommend this method (because it is highly inefficient, in just about every way I can think of).

    #!/usr/bin/perl -w use strict; use Algorithm::Permute; $| = 1; my @spinner = ('|', '/', '-', '\\'); my $bigscale = 100_000; my $scale = 100; my $index = 0; my $draw_max = 9; my $draw_min = 1; my $to_draw = 6; my (%seen); my (@res); my $p = new Algorithm::Permute([$draw_min .. $draw_max]); while (@res = $p->next) { my $st = join(', ', sort(@res[0 .. ($to_draw - 1)])); $seen{$st} = 1; print $spinner[($index++ / $scale) % 4], "\b"; print '.' unless ($index % $bigscale); } print join "\n", sort keys %seen;
Re: Lottery combinations golf
by Roger (Parson) on Oct 12, 2003 at 10:43 UTC
    This problem is covered in elementary statistics first year university. The number of combinations can be calculated with the following formula:
    X N = C Y
    Which stands for give me the number of combinations by picking Y items from a total of X number of items. The mathematical expansion of the above formula becomes:
    X X(x) * X(x-1) * ... * X(y+1) N = C = ---------------------------- Y 1 * 2 * ... (x - y)
    To pick 6 numbers from 7 numbers = 7C6 = 7/1 = 7 possible ways.

    To pick 6 numbers from 8 numbers = 8C6 = 8*7/1*2 = 28.

    To pick 6 numbers from 9 numbers = 9C6 = 9*8*7/1*2*3 = 84.

    The perl for calculating the number of combinations is thus:
    use strict; sub xCy() { my ($x, $y) = @_; return(0) if $x < $y; # can not pick more number than given return(1) if $x == $y; # 1 combination if X = Y my $diff = $x - $y; my $n = 1; for (0 .. $diff-1) { $n *= $x - $_ } my $m = 1; for (1 .. $diff) { $m *= $_ } return $n / $m; } printf "%d\n", &xCy($_, 6) for 7 .. 10; __END__ 7 28 84 210
Re: Lottery combinations golf
by CombatSquirrel (Hermit) on Oct 12, 2003 at 09:15 UTC
    Not the Perlish way, but let's look at it mathemagically:
    If you have n Numbers and 6 are drawn, there will be (n-6), which are not drawn. Let's say all seven number are drawn, but just the first 6 count. There are n! possibilities to draw all the numbers, but the first six numbers can appear in 6! different ways and the other numbers in (n-6)! different ways. Thus, you have n! / ( 6! * ( n - 6 )! ). This is the binomial coefficient C(n, 6). (In the above explanation n! is the factorial of n, where n! = n * (n - 1)! * ... * 2 * 1).
    Now C(6, 6) = 1; C(7, 6) = 7; C(8, 6) = 28; C(9, 6) = 84
    Hope this helped.
    CombatSquirrel.
    Update: This is exactly Anonymous Monk's program above :).
    Entropy is the tendency of everything going to hell.
Re: Lottery combinations golf
by Anonymous Monk on Oct 12, 2003 at 06:02 UTC
    call it as: lotto.pl 8
    sub f{my$n=pop;$n<2||$n*f($n-1)} ($n,$r)=(pop,6);print f($n)/(f(6)*f($n-$r)),$/
Re: Lottery combinations golf
by Anonymous Monk on Oct 12, 2003 at 05:38 UTC
    You've already begun counting combinations incorrectly. The number of unique combinations of 8 items taken 6 at a time is 28, not 56.
Re: Lottery combinations golf (77?)
by BrowserUk (Patriarch) on Oct 12, 2003 at 09:17 UTC

    There ought to be plenty to be trimmed from this...but I haven't found it.

    perl -lejoin('',1..pop)=~'(.).*(.).*(.).*(.).*(.).*(.)(?{print$1,$2,$3 +,$4,$5,$6})(?!)' 9

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    Hooray!

Re: Lottery combinations golf
by jonadab (Parson) on Oct 12, 2003 at 11:18 UTC

    Others have explained combinations, and they are correct, as far as they go. However, if you're going to apply math to the lottery, what you ought to be calculating is the expected return on your investment. It varies from state to state, but generally speaking if you calculate it you never buy lottery tickets again. HTH.HAND.


    $;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}} split//,".rekcah lreP rehtona tsuJ";$\=$ ;->();print$/

      ...what you ought to be calculating is the expected return on your investment. It varies from state to state, but generally speaking if you calculate it you never buy lottery tickets again

      People often say that, you know, and I think they're missing the point.

      There are a lot of variations on the theme of "the lottery is a tax on people who can't do math" that come up in these kind of discussions, but the fact remains it's the only form of gambling which has million-to-one payouts.

      I could gamble on horse races instead, and for a dollar I can get the excitement of dreaming of winning ... ten dollars. With the lottery, I can put down a dollar and have the excitement of dreaming of winning a million. I know the odds against it are much more than a million to one, (something like 7,000,000 to one in NSW) but that's not the point. Also, my odds of winning it are infinitely greater than yours because you don't have a ticket, due to your unfortunate ability to do math.

      I can dream...



      ($_='kkvvttuubbooppuuiiffssqqffssmmiibbddllffss') =~y~b-v~a-z~s; print
        Of course with a basic understanding of saving and investment, virtually any competent educated person in an affluent country can readily save over a million dollars in a lifetime. Of the benefits reported by those who have done so, the single biggest one is the ease of mind that comes from knowing that no short-term crisis is likely to be beyond your means.

        Conversely the average lottery winner winds up a short time later with the winnings being only a fading memory. And most people live with a justified fear of uncontrollable financial crises due to uncontrollable outside circumstances.

        But the potential lottery winner certainly gets more excitement than the plodding but fairly certain path to (modest) riches. Most people seem to find that worthwhile. At least that is how they behave.

        There are a lot of variations on the theme of "the lottery is a tax on people who can't do math"

        Sometimes when people commonly say a thing, it's a myth, or a meme that they all got from the same place. Sometimes it's because the thing is plain for anyone to figure out who does the figuring.

        but the fact remains it's the only form of gambling which has million-to-one payouts

        All forms of organised gambling, whether a lottery or casino games, are rigged heavily toward the house. Let me put it to you this way: even under optimal condition, if you could buy the tickets only at the perfect times when the ratio of the jackpot verses the probability of winning most favours you, if you could buy every ticket sold, you would lose money even before you had to pay taxes on your "winnings". You would lose money every time, without exception. If the lottery were not run by the state, it would be criminal under various laws regarding fraud and other ways of taking advantage of gullible people.

        With the lottery, I can put down a dollar and have the excitement of dreaming of winning a million.

        I can dream for free about winning a million dollars, or about inheriting a kingdom, or about anything. Dreams are free. Convincing people to pay money for something that's free is one of the oldest and best-known scams in the book.

        Also, my odds of winning it are infinitely greater than yours

        Mathematically speaking, this is a wash. My expected returns, at zero, are a good deal higher than yours.

        Look, the money is in your hands, and if you want to spend it on tickets that's your decision to make, but since you were talking about math, I just thought I'd bring up the mathematical side of the thing. If you want to buy dreams, hey, it's your money. Some people justify it by saying it's fun, and all forms of entertainment cost money. Sure, okay. But as far as the mathematics of the thing are concerned, it's an expenditure, not an investment of any kind. Ordinarily I don't trouble most people with this, because it just upsets them, but you were showing enough interest in math that I thought maybe you'd be interested.


        $;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}} split//,".rekcah lreP rehtona tsuJ";$\=$ ;->();print$/

      I'm sorry I can't give an attribution to this - what may be just another meme - but it has a certain wicked "mathlessness" about it!

      "Your best chance of winning the lotto is not to buy a ticket. The probability of your being delivered the winner's cheque due to a postal error is much higher"

      hagen
Re: Lottery combinations golf
by Abigail-II (Bishop) on Oct 12, 2003 at 17:45 UTC
    This one just prints out the number of combinations (and isn't pure Perl either).
    perl -le'$N=pop;@a=$N-5..$N;$"="*";print"@a/720"' 8|bc

    Abigail

Re: Lottery combinations golf
by sgifford (Prior) on Oct 12, 2003 at 15:16 UTC
    I've seen some posts about how to calculate the number of games being played, but not to illustrate it graphically, which is I think what you want. This does that. It's a little bit golfed, since that's what you asked for, but not too bad, so it's basically legible. The arguments to place are the number of remaining # characters to place, where to start placing, and then the list. It places a # in each of the remaining places, then calls itself recursively to place the remaining ones.
    #!/usr/bin/perl $a = $ARGV[0]; place($a-6,0,(1..$a)); sub place { if ($_[0]) { for my $c ($_[1]+2..$#_) { place($_[0]-1,$c-2,@_[2..$c-1],'#',@_[$c+1..$#_]) unless $_[$c] eq '#'; } } else { print @_[2..$#_],"\n"; } }
      This is a little golfier.
      #!/usr/bin/perl -l $a=shift;place($a-6,0,(1..$a));sub place{local$_;$_[0]||return print @ +_[2..$#_];$_[$_] ne'#'&&place($_[0]-1,$_-2,@_[2..$_-1],'#',@_[$_+1..$ +#_])for($_[1]+2..$#_)}
Re: Lottery combinations golf
by barrachois (Pilgrim) on Oct 14, 2003 at 02:41 UTC
    #!/usr/bin/perl -w use strict; # ----------------------------------------------- # Here's some golf-ish code that loops through the # given combinations, as well as a clearer rendition. # It uses a hash to eliminate duplicates, and # strings rather than an array for each combo. # I expect it can be done in many fewer strokes, # but I had fun playing around with it, anyway, # and this four liner looked obfuscated enough. # The output is listed at the end. my($N,$M)=(8,6);my%c;r($N,join('',1..$N));sub r{my($n,$s)=@_;if($n==$M){$c{$s}++unless$c{$s};}else {for(1..$N){$t=~s/$_/#/,r($n-1,$t)if(our$t=$s)=~/$_/;}}} print join($/,sort keys %c),"$/Total=",scalar(keys %c),$/; _END__ # A clearer version of the same thing. my ($N,$M) = (8,6); my %combos = (); recursive($N,join('',1..$N)); sub recursive { my ($n,$combo) = @_; if ($n==$M){ $combos{$combo}++ unless $combos{$combo}; } else { for my $i (1..$N){ if ( (my $tmp=$combo) =~ /$i/ ){ $tmp=~s/$i/#/; recursive($n-1,$tmp); } } } } print "-- Combinations of $N things with ", $N-$M, " crossed out. --\n", join("\n", sort keys %combos), "\n-- Total number is ", scalar(keys %combos), ". --\n\n"; # -------- output of the short one ------------- ##345678 #2#45678 #23#5678 #234#678 #2345#78 #23456#8 #234567# 1##45678 1#3#5678 1#34#678 1#345#78 1#3456#8 1#34567# 12##5678 12#4#678 12#45#78 12#456#8 12#4567# 123##678 123#5#78 123#56#8 123#567# 1234##78 1234#6#8 1234#67# 12345##8 12345#7# 123456## Total=28