生成范围内不包括某些数字的随机数

问题描述 投票:0回答:8

Python 中有没有一种简单的方法来生成一个范围内的随机数,不包括该范围内的某些数字子集?

例如,我知道您可以使用以下命令生成 0 到 9 之间的随机数:

from random import randint
randint(0,9)

如果我有一个列表怎么办?

exclude=[2,5,7]
,我不想被退回?

python random
8个回答
49
投票

试试这个:

from random import choice

print(choice([i for i in range(0,9) if i not in [2,5,7]]))

7
投票

尝试这样的事情:

from random import randint

def random_exclude(*exclude):
  exclude = set(exclude)
  randInt = randint(0,9)
  return my_custom_random() if randInt in exclude else randInt 
  
print(random_exclude(2, 5, 7))

6
投票

如果您有更大的列表,我建议使用集合操作,因为它们比推荐的答案明显更快。

random.choice(list(set([x for x in range(0, 9)]) - set(to_exclude)))

我对接受的答案和上面的代码进行了一些测试。

对于每个测试,我进行了 50 次迭代并测量了平均时间。 为了进行测试,我使用了 999999 的范围。

排除大小为 10 的元素:
接受的答案 = 0.1782s
这个答案 = 0.0953s

排除大小为 100 的元素:
接受的答案 = 01.2353s
这个答案 = 00.1117s

要排除大小为 1000 个的元素:
接受的答案= 10.4576s
这个答案 = 00.1009s


1
投票

这是另一种方法,不使用 random.choice 或重复自身,直到正确为止:

import random

def random_exclusion(start, stop, excluded) -> int:
    """Function for getting a random number with some numbers excluded"""
    excluded = set(excluded)
    value = random.randint(start, stop - len(excluded)) # Or you could use randrange
    for exclusion in tuple(excluded):
        if value < exclusion:
            break
        value += 1
    return value

它的作用是获取开始和结束之间的数字减去排除的数字数量。然后它会将数字加 1,直到它高于任何排除项。

让我们使用 0 到 5 之间的随机数(不包括 3)作为示例。由于我们将 5 减去 1,所以我们可以得到 0、1、2、3 或 4。但是我们想将最后的 2 向前移动 1为了防止出现 3,给我们 0、1、2、4 或 5。这不会创建一个包含排除值的列表,然后从中随机选择一个,它会获取一个值并添加到该值中,这是一个重要的时间,并且节省内存。

我进行了 Dominic Nagel 的测试(使用 time.perf_counter())来看看哪个更快:

对于 10 个元素:
这边的时间:0.00000162599899340421
他的时间:0.19212667199899441384

对于 100 个元素:
0.00000543000060133636
0.18264625200070441768

对于 1000 个元素:
0.00004090999893378467
0.21630024799902458632

对于 10000 个元素:
0.00087945000152103605
0.19593418199801818091

这个值呈指数级增长,而他的值保持在 0.2 秒左右,因此如果你要删除 10 亿个元素,我很可能会坚持使用他的值,除非你使用的是编译型编程语言。不过,这种方法可以节省大量内存,所以如果您打算这样做,那么您应该坚持使用我的方法。


1
投票

这个效果很好:

from random import choice

exclude_this = [2, 5, 7]
my_random_int = choice(list(set(range(0, 10)) - set(exclude_this)))

1
投票

使用集合(和

choice()
)是比理解列表更快的解决方案。如:

from numpy.random import randint
from random import choice
from typing import Set

def my_rand(start: int, end: int, exclude_values: Set[int] = None):
    if not exclude_values: # in this case, there are no values to exclude so there is no point in filtering out any
        return randint(start, end)
    return choice(list(set(range(start, end)).difference(exclude_values)))

timeit
所示(这些测试中的语句很混乱,并且包含冗余语句,例如
if True
,但这是为了模拟上面函数所做的检查):

  • 套装
>>> timeit.timeit(setup="from random import choice", stmt="choice(list(set(range(0, 300)).difference(set({1, 2, 3, 80, 189, 273}) if True else set())))", number=10000)
0.15672149998135865
>>> timeit.timeit(setup="from random import choice", stmt="choice(list(set(range(0, 300)).difference(set({1, 2, 3, 80, 189, 273}) if True else set())))", number=10000)
0.1651422999566421
>>> timeit.timeit(setup="from random import choice", stmt="choice(list(set(range(0, 300)).difference(set({1, 2, 3, 80, 189, 273}) if True else set())))", number=10000)
0.16615699999965727
  • 理解力:
>>> timeit.timeit(setup="from random import choice", stmt="choice([i for i in range(0, 300) if True and i not in set({1, 2, 3, 80, 189, 273})])", number=10000)
0.8613313999958336
>>> timeit.timeit(setup="from random import choice", stmt="choice([i for i in range(0, 300) if True and i not in set({1, 2, 3, 80, 189, 273})])", number=10000)
0.9154910000506788
>>> timeit.timeit(setup="from random import choice", stmt="choice([i for i in range(0, 300) if True and i not in set({1, 2, 3, 80, 189, 273})])", number=10000)
0.9114390999311581

0
投票

这是一篇旧文章,但也许其他人需要一个想法。 为了避免浪费时间循环获取有用的随机数,我建议您使用 for 循环

[0,1,....9,]
创建一个从 0 到 9 的列表。然后你随机洗牌一次这个列表。
[ 4,8,0,....1]
要获得随机数,只需每次需要随机数时“轮询”此列表中的第一个数字(下次读取时该随机数将不存在于列表中)。

您可以从列表中删除该数字或使用索引来解析打乱后的列表。


0
投票
import random 

def randint_with_exclude(x : int, y: int, exclude=None):
    if exclude is None:
        exclude = []
    v: int = random.randint(x, y)
    while v in exclude:
        v: int = random.randint(x, y)
    else:
        return v
© www.soinside.com 2019 - 2024. All rights reserved.