生成大的随机序列的唯一数字

时间:2013-04-27 12:10:43

标签: python random

我需要填写一个文件,其中包含许多由数字标识的记录(测试数据)。记录数量非常大,id应该是唯一的,记录的顺序应该是随机的(或伪随机的)。

我试过了:

# coding: utf-8
import random

COUNT = 100000000

random.seed(0)
file_1 = open('file1', 'w')
for i in random.sample(xrange(COUNT), COUNT):
    file_1.write('ID{0},A{0}\n'.format(i))
file_1.close()

但它正在吃掉我所有的记忆。

有没有办法生成一个连续的大洗牌序列(不一定但它会很好,否则是唯一的)整数?使用生成器而不是将所有序列保存在RAM中?

4 个答案:

答案 0 :(得分:9)

如果问题中有1亿个数字,那么这实际上是可以在内存中管理的(大概需要0.5 GB)。

正如DSM指出的那样,这可以通过标准模块以有效的方式完成:

>>> import array
>>> a = array.array('I', xrange(10**8))  # a.itemsize indicates 4 bytes per element => about 0.5 GB
>>> import random                                                               
>>> random.shuffle(a)

也可以使用第三方NumPy软件包,它是用于以有效方式管理数组的标准Python工具:

>>> import numpy
>>> ids = numpy.arange(100000000, dtype='uint32')  # 32 bits is enough for numbers up to about 4 billion
>>> numpy.random.shuffle(ids)

(这仅在您的程序已经使用NumPy时才有用,因为标准模块方法效率很高)。


这两种方法在我的机器上花费大约相同的时间(可能是1分钟的洗牌),但是它们使用的0.5 GB对于当前的计算机来说并不是太大。

PS 有太多的元素让重排变得非常随机,因为与使用的随机生成器的周期相比,可能存在太多的排列。换句话说,Python shuffle的数量少于可能的shuffle数量!

答案 1 :(得分:4)

也许类似的东西(不会是连续的,但会是唯一的):

from uuid import uuid4

def unique_nums():  # Not strictly unique, but *practically* unique
    while True:
        yield int(uuid4().hex, 16)
        # alternative yield uuid4().int

unique_num = unique_nums()
next(unique_num)
next(unique_num) # etc...

答案 2 :(得分:0)

您可以通过阅读(在Linux上)/dev/urandom或使用os.urandom()struct.unpack()轻松获取随机int:

  

返回一串适合加密使用的n个随机字节。

     

此函数返回来自OS特定随机源的随机字节。对于加密应用程序,返回的数据应该是不可预测的,尽管其确切的质量取决于操作系统的实现。在类UNIX系统上,这将查询 / dev / urandom ,在Windows上,它将使用 CryptGenRandom 。如果未找到随机源,则会引发 NotImplementedError

>>> for i in range(4): print( hex( struct.unpack('<L', os.urandom(4))[0]))
... 
0xbd7b6def
0xd3ecf2e6
0xf570b955
0xe30babb6

另一方面random包裹:

  

但是,完全确定性,它并不适用于所有目的,并且完全不适合加密目的。

如果您真的需要唯一记录,则应使用thisanswer provided by EOL

但是假设真的是随机源,可能重复的字符,你会1/NN = 2 ** sizeof(int)*8 = 2 ** 32)在第一次猜测时击中项目的机会,因此你可以获得(2**32) ** length个可能的输出。

另一方面,当using just unique results you'll have max

product from i = 0 to length {2*32 - i} 
               = n! / (n-length)!
               = (2**32)! / (2**32-length)!

!是阶乘的,而非逻辑否定。所以你只会减少结果的随机性。

答案 3 :(得分:0)

这个会让你的记忆保持正常,但可能会杀死你的磁盘:)

它生成一个文件,其序列号为0到100000000,然后随机选择其中的位置并写入另一个文件。必须在第一个文件中重新组织这些数字,以“删除”已经选择的数字。

import random

COUNT = 100000000

# Feed the file
with open('file1','w') as f:
    i = 0
    while i <= COUNT:
        f.write("{0:08d}".format(i))
        i += 1

with open('file1','r+') as f1:
    i = COUNT
    with open('file2','w') as f2:
        while i >= 0:
            f1.seek(i*8)
            # Read the last val
            last_val = f1.read(8)
            random_pos = random.randint(0, i)
            # Read random pos
            f1.seek(random_pos*8)
            random_val = f1.read(8)
            f2.write('ID{0},A{0}\n'.format(random_val))
            # Write the last value to this position
            f1.seek(random_pos*8)
            f1.write(last_val)
            i -= 1
print "Done"