[Tutor] Use functions re avoid Re: Can the following algorithmbe improved?
Nathan Pinno
falcon3166 at hotmail.com
Tue Aug 9 23:35:30 CEST 2005
It printed 25.973 as the result.
---------------------------------------------------------------
Early to bed,
Early to rise,
Makes a man healthy, wealthy, and wise.
--Benjamin Franklin
-------------------------------------------------------------------
----- Original Message -----
From: "Brian van den Broek" <bvande at po-box.mcgill.ca>
To: "Nathan Pinno" <falcon3166 at hotmail.com>
Cc: "Tutor mailing list" <tutor at python.org>
Sent: Tuesday, August 09, 2005 3:23 PM
Subject: Re: [Tutor] Use functions re avoid Re: Can the following
algorithmbe improved?
> Nathan Pinno said unto the world upon 2005-08-09 15:35:
>> Hey all,
>>
>> I just fixed it so that it prints. The problem was that it returned the
>> cards instead of printing them.
>>
>> Nathan
>
> >
> >> Hey Brian and all,
> >>
> >> Just coded in and tried your program Brian. Doesn't print a thing.
> >>
>
>
> Hi Nathan,
>
> yes, I should have pointed out that I made it return the cards dealt
> rather than printing them and explained why I made it do that. But, I just
> did it out of force of habit, so I didn't notice I'd changed the
> functionality. Sorry about that.
>
> So, why do that? Well, it might not matter too much in this case, but the
> idea is to make each function responsible for one thing. That has several
> advantages. The two main ones IMO: 1) it keeps the functions small which
> aids comprehension and debugging, and 2) it makes the functions easier to
> string together to do other things.
>
> For instance, if what you want right now is for the cards to be printed,
> it is easy enough to use something like my code[*] and then have another
> function which calls the dealing function and prints the results. If later
> you should want to use the results of a deal in a more elaborate manner
> than just printing them (like if you make a card game which needs to know
> what was dealt) you've got the deal returned and you can do with it what
> you want to. If you don't return and just print from the sort of code I
> gave, new uses will probably require changing the code rather than just
> adding new function to work with it.
>
> One approach would say don't add it now; instead do the minimal thing that
> meets your needs because just thinking you will need it later doesn't mean
> you will. But, in the case at hand, the future need is pretty likely, and
> the modularity of functions (one chunk doing the generation, the other
> doing the processing of the results) also speaks for doing it the return
> way.
>
> [*] But don't use my code. I was doing by hand what Roel pointed out can
> be done by the random module itself. (Thanks, Roel! I didn't know about
> random.sample.) Since whoever added sample to random is a better
> programmer than you or I, use sample :-)
>
>
>>> I thought the odds were more like 6/52! or 1/(1.3443029195*10^84).
>
> <snip>
>
>>>> Good question. But notice that your code has the same problem. Nothing
>>>> stops the (dramatically unlikely) even that a-u all get assigned the
>>>> same
>>>> card. Over 6 cards, it will certainly turn up that you have given the
>>>> same
>>>> card twice with this code, too. (The way I figure it:
>>>>
>>>> >>> ( (52**6) - (52*51*50*49*48*47.0) ) / (52**6)
>>>> 0.25858966166881681
>>>>
>>>> 25% of the time.)
>
> I don't think I got the math wrong. My thinking is there are 52**6 ways to
> choose 6 items from 52 if you don't care about duplicates, and
> 52*51*50*49*48*47 ways to choose if you do. (The first card can be any one
> of 52, the second any one of the 51 left, etc. 52! by contrast gives you
> all the ways 52 items can be ordered in a non-repeating sequence.)
>
> Here is a very quick (and I am sure not too efficient) bit of code to give
> empirical support to my analysis:
>
> <code>
> import random
>
> def get_choice(n, source):
> '''Returns a sequence of n independent random choices from source'''
> choice = []
> for i in range(n):
> choice.append(random.choice(source))
> return choice
>
> def has_dups(sequence):
> '''Returns True if sequence contains duplicates, False otherwise'''
> for i in sequence[:-1]:
> # No point checking the last member
> if sequence.count(i) > 1:
> # We can bail, as duplicate found
> return True
> return False
>
> def get_dup_percentage(runs, choice_length, source_length):
> '''Returns percentage of duplicates in a series of choices over a
> sequence.
>
> The function make runs many choices of length choice_length from a
> sequence
> of length source_length and returns percentage of those choices that
> contain duplication.'''
> count = 0.0 # 0.0 for type coercion
> dups = 0
> source_sequence = range(source_length)
> while count < runs:
> choice_sequence = get_choice(choice_length, source_sequence)
> if has_dups(choice_sequence):
> dups += 1
> count += 1
> return dups / count * 100
>
> print get_dup_percentage(100000, 6, 52)
> </code>
>
> Run that and I think you will find the values cluster around 25.85%.
>
> (The code was written to be general. Play around with the values in the
> final [print] line. I get that 9 choices are enough over a 52 termed
> sequence to give you more than 50% odds of duplicates.)
>
> Best,
>
> Brian vdB
>
>
More information about the Tutor
mailing list