来自两个不重叠范围的Python随机唯一值

时间:2015-05-15 03:46:40

标签: python random

由于title表示来自两个范围的100个随机唯一值或更准确,因此有一个范围和一个从有效值中排除的子范围。

示例的范围为0到10000,随机的100个数字不在10到20的范围内

要求:

  • Subrange可以在最开始或最后。
  • 内存开销至绝对最小值。
  • 随机化尽可能接近random.shuffle()。

我知道random.sample(xrange(0,10000),100)给出了100个唯一值。

设置我会存储三个值[start,end,total]

  1. start =子范围的开始
  2. end =子范围结束
  3. total =范围的长度
  4. 我能想到的最好:

    randlist=[]
    while len(randlist)<100:
        temp=random.randint(0,total)
        if temp < start or temp > end:
           if temp not in randlist:
               randlist.append(temp)
    

    这是真正的随机(伪随机)还是我以任何方式影响它?

4 个答案:

答案 0 :(得分:3)

randlist = [r + (end - start + 1) * (r >= start) for r in
            random.sample(range(total - end + start), 100)]

示例/“证据”:

  • total = 10,start = 2,end = 5
  • 有7个允许的数字:0,1,6,7,8,9,10
  • 范围(总计结束+开始)=范围(7)从7个数字中挑选0..6(到目前为止一直很好)
  • 大于或等于start = 2的数字向上移动end-start + 1 = 4
  • 产生的数字分别为0,1,6,7,8,9,10。

演示:

>>> sorted(randlist2(2000000000, 10000000, 1900000000))
[176827, 3235435, 3278133, 3673989, 5148447, 8314140, 8885997, 1900189345, 1902880599,
...
1997494057, 1997538971, 1997854443, 1997907285]

直到超过20亿,轻松击败“维基百科英文维基百科页面的数量所需的上限,所以无论数百万是” :-)。之后它获得OverflowError: Python int too large to convert to C ssize_t。我看到我的电脑内存使用量没有飙升,结果是即时的。显然,这是使用Python 3。

答案 1 :(得分:1)

尝试以下功能:

def rand_choice(start, end, amount, istart, iend):
    from random import randint
    all = []
    for i in range(amount):
        randnum = istart
        while randnum in range(istart, iend+1) or randnum in all:
            randnum = randint(start, end)
        all.append(randnum)
    return all
>>> rand_choice(1, 1000, 10, 10, 20)
[30, 798, 427, 229, 943, 386, 749, 925, 520, 877]
>>> rand_choice(1, 1000, 10, 10, 20)
[414, 351, 898, 813, 91, 205, 751, 269, 360, 501]
>>> 

答案 2 :(得分:1)

只是略有变化:

def randlist(total, start, end):
    import random
    randset = set()
    while len(randset) < 100:
        temp = random.randint(0, total)
        start <= temp <= end or randset.add(temp)
    return random.sample(randset, 100)

答案 3 :(得分:1)

之前的另一位回答者有一个非常酷的想法,即将范围连接成一个Sequence类。代码有一些问题,但我设法创建了一个似乎与random.sample一起使用的版本。

import collections, random

class range_duo(collections.Sequence):
    def __init__(self, r1, r2):
        self.r1 = r1
        self.r2 = r2
        self.l1 = len(r1)
        self.l2 = len(r2)
        self.total_length = len(r1) + len(r2)

    def __len__(self):
        return self.total_length

    def __getitem__(self, key):
        if key < self.l1:
            return self.r1[key]
        else:
            return self.r2[key-self.l1]


# Solving the example in the original question:
rd = range_duo(range(0, 10), range(20, 10000))
sample = random.sample(rd, 100)
print(sample)

显然这个类并不完美,但我唯一的目标是使用最小的内存占用来解决random.sample的问题。在Python 2.x中,应使用xrange代替range