独特的随机文件选择器生成器
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
循环中对列表进行切片或以其他方式操作。
我有一个包含大量文件的目录。我不想将所有文件名都保存在内存中,但我想使用生成器随机获取这些文件的一个子集。
我可以使用在 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
循环中对列表进行切片或以其他方式操作。