更有效的算法,在Python中随机选择抽奖获胜者

时间:2016-01-31 11:06:04

标签: python memory random

我试图找到一个代码来从所有生成的抽奖中选择一个随机获胜者,并且有更快的方法可以更快地生成更多的抽奖活动,如果是这样的话会产生数百万。到目前为止,这是我的代码。

import random 

def genNumber(n = 4):
    return "".join([str(random.randint(0,9)) for i in range(n)])

for i in range(12365):
    word = random.choice(['blue', 'aqua', 'jade','plum', 'gold', 'navy', 'pink', 'grey', 'ruby', 'rose', 'teal',"lime",]) 
    print("{} {} {}".format(word.title(), genNumber(4), genNumber(4)))
random.choice(word)

1 个答案:

答案 0 :(得分:4)

您当前的抽奖券生成算法存在一个问题:可能多次生成同一张票。防止这种情况的一种简单方法是按顺序生成故障单。如果您想随机生成门票,也可以这样做,但您需要跟踪生成的所有门票以防止重复。

下面的代码会创建一个列表,列出所有有效的票号,列表中的随机数,然后将每个数字转换为颜色+数字字符串。我的代码只生成简单的数字字符串,但如果需要,可以很容易地修改它以创建xxxx xxxx形式的数字。

首先,我将说明进行转换的功能。

    colors = ['Blue', 'Aqua', 'Jade',]
    num_colors = len(colors)

    def num_to_ticket(n):
        return '{0} {1}'.format(colors[n % num_colors], n // num_colors)

    num_tickets = 15
    for n in range(num_tickets):
        print(num_to_ticket(n))

<强>输出

Blue 0
Aqua 0
Jade 0
Blue 1
Aqua 1
Jade 1
Blue 2
Aqua 2
Jade 2
Blue 3
Aqua 3
Jade 3
Blue 4
Aqua 4
Jade 4

现在这里是洗牌并随机选择一张的代码。此代码使用random.seed函数,以便结果可重现。如果您不打电话给random.seed,或者如果您使用None(即random.seed(None))参数调用它,那么伪随机序列将以随机数播种由操作系统提供,因此每次运行程序时结果都会有所不同。

来自random module docs

  

random.seed(a=None, version=2)

     

初始化随机数生成器。

     

如果省略aNone,则使用当前系统时间。如果   随机源由操作系统提供,它们被使用   而不是系统时间(参见os.urandom()函数   可用性详情。

from random import seed, randrange, shuffle

colors = [
    'Blue', 'Aqua', 'Jade', 
    #'Plum', 'Gold', 'Navy',
    #'Pink', 'Grey', 'Ruby', 
    #'Rose', 'Teal', 'Lime',
]
num_colors = len(colors)

def num_to_ticket(n):
    return '{0} {1}'.format(colors[n % num_colors], n // num_colors) 

seed(1234)

num_tickets = 15

tickets = range(num_tickets)
shuffle(tickets)
for n in tickets:
    print(num_to_ticket(n))

winner = randrange(num_tickets)
print('\nWinner:', num_to_ticket(winner))

<强>输出

Aqua 1
Jade 0
Jade 2
Blue 1
Aqua 2
Aqua 0
Blue 3
Blue 4
Aqua 4
Jade 1
Jade 3
Aqua 3
Blue 0
Blue 2
Jade 4

Winner: Blue 3

如果您正在使用Python 3,则需要更改此行:

tickets = range(num_tickets)

到此:

tickets = list(range(num_tickets))

在配备2GB内存的旧款2 GHz机器上,我可以在30秒左右的时间内洗牌10000000张。

这是一个修改后的版本,以Jade 0038 0763格式打印票证。它还允许您指定要生成的获胜者数量。如果您希望每次只是为seed提供一个新参数,或者只是完全删除seed来电。

from __future__ import print_function
from random import seed, randrange, shuffle, sample

colors = [
    'Blue', 'Aqua', 'Jade', 
    #'Plum', 'Gold', 'Navy',
    #'Pink', 'Grey', 'Ruby', 
    #'Rose', 'Teal', 'Lime',
]
num_colors = len(colors)

def num_to_ticket(n):
    color = colors[n % num_colors]
    num = str(n // num_colors).zfill(8)
    return '{0} {1} {2}'.format(color, num[:4], num[4:])

seed(1234)

num_tickets = 15
num_winners = 4

tickets = range(num_tickets)
shuffle(tickets)
for n in tickets:
    print(num_to_ticket(n))

#Select winners
winners = sample(tickets, num_winners)
for i, num in enumerate(winners):
    print('Winner #{0}: {1}'.format(i, num_to_ticket(num)))

<强>输出

Aqua 0000 0001
Jade 0000 0000
Jade 0000 0002
Blue 0000 0001
Aqua 0000 0002
Aqua 0000 0000
Blue 0000 0003
Blue 0000 0004
Aqua 0000 0004
Jade 0000 0001
Jade 0000 0003
Aqua 0000 0003
Blue 0000 0000
Blue 0000 0002
Jade 0000 0004
Winner #0: Jade 0000 0001
Winner #1: Jade 0000 0002
Winner #2: Blue 0000 0002
Winner #3: Jade 0000 0000

这里是&#34;获胜者&#34;的输出。我将num_tickets更改为1500000

时的代码部分
Winner #0: Jade 0038 0763
Winner #1: Jade 0033 4760
Winner #2: Aqua 0034 9232
Winner #3: Jade 0046 6305

我的机器需要大约5秒钟。

这里的另一个版本应该更符合您的喜好...但是,它确实运行得更慢:生成1,500,000张票(不打印它们)在我的机器上大约需要12秒。

''' Generate random raffle tickets, and select winners

    See http://stackoverflow.com/q/35113113/4014959

    Written by PM 2Ring 2016.02.01
'''

from __future__ import print_function
from random import seed, randrange, shuffle, sample

colors = [
    'Blue', 'Aqua', 'Jade', 
    'Plum', 'Gold', 'Navy',
    'Pink', 'Grey', 'Ruby', 
    'Rose', 'Teal', 'Lime',
]
num_colors = len(colors)

def num_to_ticket(n):
    color = colors[n % num_colors]
    num = str(n // num_colors).zfill(8)
    return '{0} {1} {2}'.format(color, num[:4], num[4:])

seed(1234)

num_tickets = 15
num_winners = 4

tickets = set()
while len(tickets) < num_tickets:
    ticket = randrange(1200000000)
    tickets.add(ticket)

for n in tickets:
    print(num_to_ticket(n))

#Select winners
winners = sample(tickets, num_winners)
for i, num in enumerate(winners, 1):
    print('Winner #{0}: {1}'.format(i, num_to_ticket(num)))

<强>输出

Pink 6158 1569
Blue 0074 9147
Pink 3460 8896
Pink 6232 8147
Ruby 9392 6899
Jade 9109 7596
Lime 4407 3259
Ruby 0839 3822
Aqua 6715 6348
Pink 9664 5353
Pink 2368 0977
Jade 0308 1402
Plum 7664 8093
Ruby 7887 7271
Plum 5822 2757
Winner #1: Pink 3460 8896
Winner #2: Plum 5822 2757
Winner #3: Blue 0074 9147
Winner #4: Pink 6158 1569