独特的随机文件选择器生成器

Unique Random File Selector Generator

我有一个包含大量文件的目录。我不想将所有文件名都保存在内存中,但我想使用生成器随机获取这些文件的一个子集。

我可以使用在 post“Best way to choose a random file from a directory”中找到的信息来执行此操作,但我想确保我的生成器永远不会 return 对同一个文件重复两次。所以最终在 运行 生成器(这将 return 批次)之后我会循环遍历目录中的整个文件列表。

我能想到的方法仍然会创建一个文件列表来进行比较(创建一个已经使用过的文件名的列表,如果不在列表中则 return)并且生成器执行的次数越多,执行时间就越长产生了结果。

有没有办法,如果我创建一个数字数组,该数组等于目录中的文件数,当我从数组中随机弹出一个值时,我可以在该位置获取文件? (我认为这比字符串数组占用的内存要少得多)

根据当前的评论,我有以下代码:

def GetRandomFileListGenerator(self, path):

    fileList = [f for f in listdir(path) if isfile(join(path, f))]
    random.shuffle(fileList)

    while(self.batchSize < len(fileList)):
        yield fileList[:self.batchSize]
        fileList = fileList[self.batchSize:]

您可以通过添加 set 来调整您提到的问题的解决方案并检查其长度。这是一个例子:

import os
import random

random_filenames = set()
all_files = os.listdir("./")

while len(random_filenames) < 5:
    random_filenames.add(random.choice(all_files))

至于内存消耗,你仍然需要加载整个文件列表,除非你使用一些文件名模式来避免列出并使用 itertools.cycle 循环它并跳过随机数量的文件。

我在评论中提到了这个方法,但不知道我解释得好不好,所以我在这里详细说明。

您可以使用 random.sample 从集合中获取多个值而不重复。

import random

def iterate_over_files_randomly():
    the_filenames = ["a", "b", "c", "d", "e", "f"]
    for filename in random.sample(the_filenames, len(the_filenames)):
        yield filename

for filename in iterate_over_files_randomly():
    print(filename)

您也可以打乱列表并对其进行迭代。

import random

def iterate_over_files_randomly():
    the_filenames = ["a", "b", "c", "d", "e", "f"]
    random.shuffle(the_filenames)
    for filename in the_filenames:
        yield filename

for filename in iterate_over_files_randomly():
    print(filename)

在任何一种情况下,生成器都会遍历目录中的整个文件列表,在以后的任何采样中都不会重复,直到文件列表用完为止。示例输出:

b
c
f
e
d
a

两种方法都有 O(N) 运行 时间。换句话说,产生的每个附加值所花费的时间与产生先前值所花费的时间相同。这部分是由于生成器函数不会在其 for 循环中对列表进行切片或以其他方式操作。