tips for this exercise?

Steven D'Aprano steve at REMOVETHIScyber.com.au
Tue Mar 28 18:01:43 EST 2006


On Tue, 28 Mar 2006 20:32:32 +0000, John Salerno wrote:

> Brian Quinlan wrote:
> 
>> I would just write the function like this:
>> 
>> def genNumbers():
>>     shuffle_nums = numbers[:]    # copy the list to preserve the orginal
>>                                  # order (if it matters)
>>     random.shuffle(shuffle_nums) # shuffle the entire list
>>     return shuffle_nums[:5]      # return the first 5 elements
> 
> Thanks. Interesting idea. I did consider copying it, but does that hurt 
> performance each time the function is called? I know it may not be 
> noticeable, but I don't like the idea of doing unnecessary work like 
> that, if it is in fact unnecessary.

Generally, lottery numbers are selected from a range, e.g. one to forty.
So rather than passing a global list, just pass the maximum number:

def getNumbers(maxn=40):
    L = range(1, maxn+1)
    random.shuffle(L)
    return L[0:5]

This recreates the master list as needed. If you are running a lot of
trials, or if your maxn is huge (in the tens of millions perhaps) you
might want to optimize by re-using the list each time:

all_numbers = range(1, maxn+1)

def getNumbers(L):
    random.shuffle(L)
    return L[0:5]

getNumbers(all_numbers)

Notice that this has the side-effect of shuffling your master list. In
general, side-effects are to be avoided whenever possible, although this
one is fairly benign.

However, and this is important, consider this note from the random.shuffle
__doc__ string:
     
    Note that for even rather small len(x), the total number of
    permutations of x is larger than the period of most random number
    generators; this implies that "most" permutations of a long
    sequence can never be generated.

In other words, this is not a good technique for producing a fair lottery.
The results will be biased.

Here is a method that is less biased:

def genNumbers(maxn=40):
    # Warning: untested
    L = range(1, maxn+1)
    chosen = []
    for _ in range(5):
        n = random.choice(L)
        L.remove(n)
        chosen.append(n)
    return chosen

If you want to allow duplicates, you can simplify the code:

def genNumbersWithDuplicates(maxn=40):
    # Warning: untested
    L = range(1, maxn+1)
    chosen = []
    for _ in range(5):
        chosen.append(random.choice(L))
    return chosen


Hope this helps.


-- 
Steven.




More information about the Python-list mailing list