如何计算循环函数的第一次重复?

How to calculate first repetition of a looping function?

我是 Python 的新手,对以下作业有疑问。

import random
print(random.randint(1, 100))

如何计算重复的随机数(使用字典)?

输出应该是这样的:

    >>> repeat (1, 100)
    ([random1, random2, random3, ...], number of loops until the first repetition is reached)

谢谢。

您可以只初始化一个集合,然后循环获取一个随机数并检查它是否已经在集合中,如果是则退出,否则将其添加到集合并继续。

不是使用字典,而是函数 repeat:

import random
def repeat(a, b):
    l = []
    while True:
        l.append(random.randint(a, b))
        if len(set(l)) != len(l):
            break
    return l

print(repeat(1, 100))

输出:

[13, 76, 32, 41, 59, 34, 43, 91, 28, 17, 53, 20, 46, 67, 37, 88, 16, 6, 92, 34]

你可以保留一个列表,并在该列表中不断添加你的随机数,当你发现你的随机数已经在你的列表中时,你就打破循环注意这是一个 O(n) 解决方案正弦您需要在整个列表中找到该元素

import random

my_list = []

while True:
    #Generate random number
    i = random.randint(1, 100)
    #If it is already in the list, break the loop
    if i in my_list:
        break
    #Append random number to list
    my_list.append(i)

print(my_list)

输出可能看起来像

[5, 58, 84, 53]
[5, 29, 64, 52, 69, 53, 72, 41, 58, 50, 4, 68, 67, 22, 90, 32, 45, 17, 47, 89, 55, 6, 7, 46, 37, 88]
[17, 65, 46, 84, 30, 100, 48, 31, 80, 97, 70, 86, 47, 81, 13, 85, 60, 63, 22, 68, 8, 36, 99]
.....

@6502 已经指出的 O(1) 建议是将随机数附加为字典的键,这样查找会更快 O(1)

import random

my_dict = {}

while True:
    #Generate random number
    i = random.randint(1, 100)
    #If it is already in the keys of dict, break the loop
    if i in my_dict:
        break
    #Append random number as key of dict with value 0
    my_dict[i] = 0

print(list(my_dict.keys()))

我们实际上可以使用 timeit 模块来检查改进,尽管它并不明显,因为随机数大小只有 1-100

首先是列表方法

In [21]: import random 
    ...:  
    ...: def get_list(): 
    ...:     my_list = [] 
    ...:     while True: 
    ...:         #Generate random number 
    ...:         i = random.randint(1, 100) 
    ...:         #If it is already in the list, break the loop 
    ...:         if i in my_list: 
    ...:             break 
    ...:         #Append random number to list 
    ...:         my_list.append(i) 
    ...:     return my_list 
    ...:                                                                                                                                                                                                              

In [22]: %timeit get_list()                                                                                                                                                                                           
16.9 µs ± 720 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

然后是字典方法

In [27]:                                                                                                                                                                                                              

In [27]: import random 
    ...:  
    ...: def get_list(): 
    ...:     my_dict = {} 
    ...:     while True: 
    ...:         # Generate random number 
    ...:         i = random.randint(1, 100) 
    ...:         # If it is already in the keys of dict, break the loop 
    ...:         if i in my_dict: 
    ...:             break 
    ...:         # Append random number as key of dict with value 0 
    ...:         my_dict[i] = 0 
In [29]: %timeit get_list()                                                                                                                                                                                           
16.1 µs ± 567 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

但是如果我们使用 1-10000 的范围,差异是明显的

In [38]: import random 
    ...:  
    ...: def get_list(upper): 
    ...:  
    ...:     my_list = [] 
    ...:     while True: 
    ...:         # Generate random number 
    ...:         i = random.randint(1, upper) 
    ...:         # If it is already in the list, break the loop 
    ...:         if i in my_list: 
    ...:             break 
    ...:         # Append random number to list 
    ...:         my_list.append(i) 
    ...:                                                                                                                                                                                                              

In [39]: %timeit get_list(10000)                                                                                                                                                                                      
287 µs ± 5.21 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [40]: import random 
    ...:  
    ...: def get_list(upper): 
    ...:    
    ...:     my_dict = {} 
    ...:  
    ...:     while True: 
    ...:         # Generate random number 
    ...:         i = random.randint(1, upper) 
    ...:         # If it is already in the keys of dict, break the loop 
    ...:         if i in my_dict: 
    ...:             break 
    ...:         # Append random number as key of dict with value 0 
    ...:         my_dict[i] = 0 
    ...:                                                                                                                                                                                                              

In [41]:  %timeit get_list(10000)                                                                                                                                                                                     
155 µs ± 2.48 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

您可以看到列表方法花费的时间几乎是字典方法的两倍!

如果不需要维护生成数字的顺序,可以使用字典来做到这一点。

import random
def repeat_generator(min, max):
    random_dict = {}
    while True:
        random_number = random.randint(min, max)
        if random_dict.get(random_number):
            break
        else:
           random_dict[random_number] = 1
    print(random_dict.keys())

试试下面的代码。这会将每个随机数添加到字典中,然后使用它来检查随机数是否已经存在。你可以使用其他数据结构做同样的事情,但是,因为你提到了字典,所以我在这里使用它。

import random

rand_dict = {}

i = 0
while True:
    rand_num = random.randint(1,100)
    if rand_num in rand_dict:
        print("random number already in dict. rand_num = %s, Number of Loops = %s" %(rand_num, i))
        break
    else:
        i += 1
        rand_dict[rand_num] = 1

输出:

random number already in dict. rand_num = 90, Number of Loops = 11

setdict更适合这里,因为你只是想记录重复,dict中的值在这里没用,O(1)次检查重复set:

import random
def repeat(a, b):
    nums = set()
    count = 0
    while len(nums) == count:
        nums.add(random.randint(a, b))
        count += 1
    return list(nums)

这是一个高级解决方案。

首先,创建一个随机数生成器:

>>> import random
>>> random.seed(100) # to make it repeatable
>>> it = iter(lambda: random.randint(1,100), -1)

这是函数的鲜为人知的形式 iter:第一个参数是一个函数,在到达哨兵之前一直被调用。由于 randint 永远不会 return -1,这是一个无限的随机数生成器:

>>> import itertools
>>> list(itertools.islice(it, 15))
[19, 59, 59, 99, 23, 91, 51, 94, 45, 56, 65, 15, 69, 16, 11]
>>> list(itertools.islice(it, 15))
[95, 59, 34, 7, 85, 83, 27, 43, 30, 40, 99, 27, 23, 19, 25]

您可以根据需要获得任意数量的随机数。 (函数 islice 采用迭代器的 "slice")。现在,我们在不知道数字的情况下取数字:

>>> seen = set()
>>> list(itertools.takewhile(lambda x: x not in seen and not seen.add(x), it))
[45, 48, 81, 53, 27, 52, 60, 72, 36, 49, 21, 84, 82, 16, 24, 1, 78, 51, 19, 100, 73]

注意副作用:我们创建一个空集 s 来存储看到的数字,并且对于每个 x,我们测试 x 是否在 seen 中(我们之前看到x然后x添加到seen。诀窍是 seen.add(x) 总是 return None,因此 not seen.add(x) 总是 Trueb and not seen.add(x) == b and True == b.

检查:

>>> random.seed(100) # to make it repeatable
>>> it2 = iter(lambda: random.randint(1,100), -1)
>>> list(itertools.islice(it2, 30, 52))
[45, 48, 81, 53, 27, 52, 60, 72, 36, 49, 21, 84, 82, 16, 24, 1, 78, 51, 19, 100, 73, 21]

21 重复了。