【问题标题】:Looking for a simple and efficient way to generate random numbers in python so that in every 10 number sequance the numbers won't repeat寻找一种在python中生成随机数的简单有效的方法,以便在每10个数字序列中数字不会重复
【发布时间】:2020-05-18 16:23:18
【问题描述】:

我想知道是否有一种简单有效的方法可以在 python 中生成随机数 这样每10个序列都是不同的数字。

我试过这个选项:

import random
random.randint(0,100)

但经过几代之后,我注意到生成的数字可以一个接一个地重复 所以我尝试使用一组这些数字,它有点解决了这个问题 但它留下了一些数字,如果我需要特定数量的随机生成的数字,我需要在之后重新生成这些数字,但过了一会儿我被建议使用另一种解决方案:

Randlist = random.sample(range(1,101), k=10)

效果很好,但需要一个整数列表来保存我的 10 个不同的数字

有没有办法在没有列表的情况下做到这一点,所以它不会像 O(n^2) 及以上那样太复杂?

【问题讨论】:

  • 像您在最后所做的那样从集合中采样可能是最直接的方法。请注意,range 不是列表。它是一个包含几个数字的对象,并根据请求按索引计算其元素。
  • @Carcigenicate 即使我这样做: import random print(random.sample(range(1,101), k=10), end = ' ') 它仍然将它们打印为列表..
  • 您会接受 [0,1,2,3,4,5,6,7,8,9, 9] 作为有效(如果不可能)输出吗?前 10 个不重复,但从第二个数字开始的 10 序列包含一个重复。
  • @Oli 如果我们谈论的是个位数而不是肯定的,但我确实想知道洗牌下一个序列需要什么。
  • 要求列表有什么问题?这是 O(1) 内存和时间。

标签: python python-3.x random


【解决方案1】:

算法

import random

def randoms():
    while True:
        yield random.randint(0,9)

def no_repeat(source_iter, length):
    seen = set()
    cycle_pos = 0
    while True:        
        n = next(source_iter)
        if n not in seen:
            yield n
            cycle_pos += 1
            seen.add(n)

            if cycle_pos == length:
                seen.clear()
                cycle_pos = 0


rep = no_repeat(randoms(), 10)

print([next(rep) for i in range(100)]) # take 100 items from the `rep` iterator and put them into a list

randoms 函数是一个生成器,可提供无限数量的随机数。 no_repeat 函数是一个生成器,它将生成器作为参数并对其进行过滤,以使长度为 10 的每个部分没有重复。

通过组合这些生成器,您可以创建一个迭代器,该迭代器在每个长度为 10 的序列中生成不重复的随机数。

复杂性

如果您假设可能的随机数范围远大于“循环长度”,那么生成 n 数字是 O(n),因为每次迭代,您都会生成一个随机数,生成它,然后添加它到集合。假设集合是一个哈希表,这个加法是O(1)(检查它是否在集合中)。如果清除一个集合是O(n),那么如果每 10 次操作执行一次,并且花费的时间与 10 成正比,那么每次迭代都会摊销到 O(1)

如果要考虑较小范围的可能数字,则对于循环长度k,在循环开始时,每次迭代为O(1),则存在1/k 的冲突概率,则为下一次迭代 2/k 概率等,直到它在 k 迭代后重置。 因此它是O(k^2 n),但是这个k 是固定的(在你的情况下它始终是10),所以实际上它可以被认为是一个常数因子,使它等同于O(n)

【讨论】:

  • 有趣的方法,这个复杂度是多少?
  • @AlexButane 编辑了一些非正式的百里香复杂性内容:)
  • 我不想小气,但是生成随机数直到你找到一个有效的数字比仅仅打乱一个有效数字列表的效率要低
  • @fafl 这取决于您希望随机数具有哪些属性。如果您要生成 10 个从 1 到 10 的唯一数字,则生成它们需要大约 100 次迭代 O(n^2) 与 O(n) 时间来创建 10 个项目的列表和 O(n) 来打乱它们,使洗牌具有更好的复杂性。
  • 但是如果你想生成从 1 到 10000 的 10 个数字,那么你几乎不可能发生碰撞,所以大约需要 10 次迭代来生成你的数字。用混洗做同样的事情涉及大约 10000 次操作来创建 10000 个元素的列表,然后与 10000 次操作成比例的时间来混洗列表,然后只从中取出 10 个元素。此外,您的算法的每次迭代都会创建一个列表,这将涉及分配,我怀疑这会为算法增加一个很大的常数因子。
【解决方案2】:

我可能会先生成数字,然后将它们就地洗牌。像这样的:

import random

numbers = [*range(10)] * 5
random.shuffle(numbers)
print(numbers)

编辑:如果您希望数字组保持在一起,请改用它:

import random

result = []
for i in range(5):
  numbers = [*range(10)]
  random.shuffle(numbers)
  result.extend(numbers)
print(result)

【讨论】:

  • 我应该在 *range(10) 部分之前放什么?
  • 我认为这行不通,因为这会生成一个包含 5 个 1、5 个 2 ...... 和 5 个 9 的列表,然后打乱这个列表。不能保证这五个都会被放在列表的不同部分(实际上我认为它们不太可能)。
猜你喜欢
  • 1970-01-01
  • 2010-10-18
  • 2023-03-14
  • 1970-01-01
  • 2019-01-12
  • 1970-01-01
  • 1970-01-01
  • 2022-11-22
  • 2021-10-23
相关资源
最近更新 更多