0

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

我可以使用帖子“从目录中选择随机文件的最佳方式”中找到的信息来执行此操作,但我想确保我的生成器永远不会返回相同的文件两次。所以最终在运行生成器(它将返回批次)之后,我将循环浏览目录中的整个文件列表。

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

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

从当前的评论中,我有以下代码:

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:]
4

2 回答 2

1

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

您可以使用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循环中对列表进行切片或以其他方式操作。

于 2020-01-07T14:23:04.653 回答
0

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

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并跳过随机数量的文件。

于 2020-01-07T13:57:12.297 回答