【问题标题】:Choose random numbers from a range except numbers in a list从列表中的数字以外的范围中选择随机数
【发布时间】:2021-07-28 23:58:19
【问题描述】:

我有一个 for 循环,在每个循环中,我从一个恒定范围内选择一个随机数。但是,我从不想获得重复的值。这就是我现在的做法:

import random
my_range = 1000
chosen = [81, 944, 576, 618, 333, 350, 579, 774, 86, 511, 619, 552, 804, 44, 894, 408, 242]
for i in range(500):
    rand_ind = random.randint(0,1000)
    while rand_ind in chosen:
        rand_ind = random.randint(0,my_range)
    chosen.append(rand_ind)
print(chosen)

有没有什么方法可以在一行中或更有效地做到这一点?

【问题讨论】:

标签: python python-3.x random


【解决方案1】:

直接使用random.sample获取固定数量的pick,不重复。

chosen = random.sample(range(1001), 500)

如果您想在采样前排除一些数字,请使用中间 sets 以获得有效差异。

excluded = {81, 944, 576, 618, 333, 350, 579, 774, 86, 511, 619, 552, 804, 44, 894, 408, 242}
chosen = random.sample(list(set(range(1001)) - excluded), 500)

【讨论】:

  • @mistermiyagi 我不知道random.sample()。很好,我把这个答案作为我答案的一部分,它比原始问题快 15 倍以上(比我的快 50%)。
【解决方案2】:

看起来你想从set(range(1001)) - set(chosen)sample

【讨论】:

    【解决方案3】:

    根据范围的大小(假设它不是太大),我会对所有可能的项目使用随机播放。

    import random
    
    my_range = 1000
    my_item_count = my_range //2
    
    # generate all the possibilities
    choices = list(range(my_range))
    
    # randomize their order
    random.shuffle(choices)
    
    # take the first n
    choices = choices[:my_item_count]
    
    print(choices)
    

    如果我将 my_range 设置为 10 之类的数字,我们会得到如下结果:

    [7, 3, 0, 4, 8]
    

    这真的比原来的快吗?

    有一个有效的问题询问这实际上是否比原始答案更快。这似乎是一个非常合理的问题,我可能应该包括时间来演示。

    提示,如果不是,那么我不会提供它作为答案:-)

    让我们添加一些计时代码。这将比较原始答案和这个答案,但我鼓励其他人也提供答案来证明他们的改进。请注意,我添加了 Miyagi 先生的答案,因为我怀疑这将是一个电话中最快的。

    提示,它是:-)

    新计时码:

    import timeit
    
    setup_original='''
    import random
    my_range = 1_000
    my_item_count = my_range // 2
    def test(my_range, my_item_count):
        chosen = []
        for i in range(my_item_count):
            rand_ind = random.randint(0,my_range)
            while rand_ind in chosen:
                rand_ind = random.randint(0,my_range)
            chosen.append(rand_ind)
        return chosen
    '''
    
    setup_jonsg='''
    import random
    my_range = 1_000
    my_item_count = my_range // 2
    def test(my_range, my_item_count):
        choices = list(range(my_range))
        random.shuffle(choices)
        return choices[:my_item_count]
    '''
    
    setup_MisterMiyagi='''
    import random
    my_range = 1_000
    my_item_count = my_range // 2
    def test(my_range, my_item_count):
        return random.sample(range(my_range), my_item_count)
    '''
    
    print("Original: %s" % timeit.timeit("test(my_range, my_item_count)", setup=setup_original, number=1000))
    
    print("jonsg: %s" % timeit.timeit("test(my_range, my_item_count)", setup=setup_jonsg, number=1000))
    
    print("MisterMiyagi: %s" % timeit.timeit("test(my_range, my_item_count)", setup=setup_MisterMiyagi, number=1000))
    

    在我的笔记本电脑上,结果是:

    Original: 2.9269699
    jonsg: 0.3391961000000001
    MisterMiyagi: 0.2070141999999997
    

    原版大约慢了 10 倍!

    MisterMiyagi 的回答比我的快 50%!

    【讨论】:

    • 我不认为这比我已经拥有的效率高得多。特别是如果项目数比范围小很多。是吗?
    • 你试过了吗?当我在这两个选项上运行 timeit 时,你的速度要慢 10 倍。我将添加timeit代码。
    • 我做到了。那是我的错,因为我包括了一个小例子并且没有考虑它如何影响答案。在我的原始代码中,range 是 100,000,my_item_count 是 ~500。这使得这个解决方案毫无用处,因为洗牌时间太长了。但是,@MisterMiyagi 的回答也适用于这种情况。感谢您的帮助
    【解决方案4】:
    import random
    def shuffle(Arr):
        arr = [i for i in Arr]
        for i in range(len(arr) - 1):
            rndIdx = random.randint(i, len(arr)-1)
            tmp = arr[rndIdx]
            arr[rndIdx] = arr[i]
            arr[i] = tmp
        return arr
    
    In[0]: a = list(range(30)); print(a) #my_range
    Out[0]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
    
    In[1]: b = list(range(15, 25)); print(b) #chosen
    Out[1]: [15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
    
    In[2]: l = [i for i in a if i not in b]; print(l) #my_range - chosen
    Out[2]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 25, 26, 27, 28, 29]
    
    In[3]: print(shuffle(l)) #shuffled(my_range - chosen) without repeating elements
    Out[3]: [5, 2, 8, 6, 1, 26, 28, 11, 4, 7, 13, 9, 14, 29, 12, 10, 0, 27, 3, 25]
    

    【讨论】:

      猜你喜欢
      • 2019-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-15
      • 2011-12-21
      • 2020-04-18
      相关资源
      最近更新 更多