tips for this exercise?

Steven D'Aprano steve at REMOVETHIScyber.com.au
Wed Mar 29 01:01:43 CEST 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.

```