1

I am trying to make a lottery machine that generate a list of 7 winning numbers and 3 bonus numbers from 1-34. I want the bonus numbers to never pick the same numbers as the winning numbers.

winning_numbers = random.sample(range(1, 34), 7)
bonus_numbers = random.sample(range(1, 34), 3)

Is there any command/code that can exclude the numbers already picked in the previous list?

Paul
  • 26,170
  • 12
  • 85
  • 119
Erik F.S.
  • 11
  • 1
  • 1
    Yes there is :) – Willem Van Onsem Apr 11 '18 at 19:30
  • What if you kept drawing numbers until there are no matches? – Paul Apr 11 '18 at 19:35
  • 1
    Possible duplicate of [Can Python generate a random number that excludes a set of numbers, without using recursion?](https://stackoverflow.com/questions/10666661/can-python-generate-a-random-number-that-excludes-a-set-of-numbers-without-usin) – b3ko Apr 11 '18 at 19:35
  • check out this answer: https://stackoverflow.com/questions/10666661/can-python-generate-a-random-number-that-excludes-a-set-of-numbers-without-usin – b3ko Apr 11 '18 at 19:36
  • 1
    Note that if you want to include all the numbers up to and including 34, you should use `range(1, 35)`. https://docs.python.org/2/library/functions.html#range – nofinator Apr 11 '18 at 19:40

3 Answers3

2

random solution

If you want to only use the random module, you can use:

import random

nums = random.sample(range(1,35), 10)

winning_numbers = nums[:7]
bonus_numbers = nums[7:]

>>> winning_numbers
[2, 23, 29, 34, 26, 16, 13]

>>> bonus_numbers
[8, 4, 19]

As random.sample is "Used for random sampling without replacement." (Quoted from the docs)

numpy solution

You can also use numpy, as numpy.random.choice has a replace argument you can set to false. (I'm personally a fan or using numpy for random numbers, as it provides a lot more flexibility in more complex tasks than random)

import numpy as np

nums = np.random.choice(range(1,35), 10, replace=False)

winning_numbers = nums[:7]
bonus_numbers = nums[7:]


>>> winning_numbers
array([27,  4, 17, 30, 32, 21, 23])

>>> bonus_numbers
array([15, 13, 18])
sacuL
  • 49,704
  • 8
  • 81
  • 106
2

A small but not unimportant remark at the beginning:

Whether you draw first 7 numbers and then 3 from the remaining ones, or 10 right away and split them into 7 winning numbers and 3 bonus numbers is absolutely equivalent in terms of probability:

In the first case the probability for any number to become a bonus number is:

first7then3

And in the second:

all10then3

Note that the reasoning for the probability of any number being a winning number is just the same.

Implementing the first case is actually slightly longer, but still fairly simple when using set and set operations. Here is how this could look:

import random

# set of all potential numbers to draw from
all_numbers = set(range(1,35))  
# draw the winners
winning_numbers = set(random.sample(all_numbers, 7)  
# subtract the winners
remaining_numbers = all_numbers-winning_numbers  
# draw the bonus from the remaining numbers:
bonus_numbers = set(random.sample(remaining_numbers, 3)) 

The implementation of the 2nd case is minimal and could look like this:

import random

drawn_numbers = random.sample(range(1,35), 10)
winning_numbers, bonus_numbers = drawn_numbers[:7], drawn_numbers[7:]

Hope that helped and happy coding!

j-i-l
  • 10,281
  • 3
  • 53
  • 70
0

Something like this?

import random
winning_numbers = random.sample(range(1, 34), 7)
bonus_numbers = []
while 1==1:
  num = random.randint(1,34)
  if len(bonus_numbers) == 3:
    break
  if num not in winning_numbers and num not in bonus_numbers:
    bonus_numbers.append(num)