【问题标题】:Unique Random File Selector Generator独特的随机文件选择器生成器
【发布时间】:2020-04-25 00:55:18
【问题描述】:

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

我可以使用帖子“Best way to choose a random file from a directory”中的信息来做到这一点,但我想确保我的生成器不会两次返回同一个文件。所以最终在运行生成器(它将返回批次)之后,我会循环浏览目录中的整个文件列表。

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

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

从当前的 cmets 我有以下代码:

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

【问题讨论】:

  • “我认为这将比字符串数组占用更少的内存”。好吧,定义“显着减少”。在我的机器上,一个整数是 14 个字节,一个字符串是 25+len(the_string) 个字节,所以对于有十几个字符左右的字符串,使用整数列表只会将内存使用量减少三倍。除非您已经对系统的限制感到紧张,否则任何低于一个数量级的节省对我来说似乎都不值得。
  • 如果您放弃整数数组要求,那么从集合中选择 N 个唯一元素很容易 - 只需调用 random.sample(the_filenames, N)
  • 至于“选择随机索引”:请注意,通常不能保证目录中的文件是有序的!
  • 没问题,拨打random.sample(the_filenames, len(the_filenames))即可。然后它将遍历每个文件名一次,然后变得筋疲力尽。或者,在迭代之前调用列表上的random.shuffle 一次。
  • 如果文件被添加/删除到目录生成器正在生成路径会发生什么?

标签: python random generator file-listing


【解决方案1】:

我在cmets中提到过这种做法,不知道我解释的好不好,这里再详细说明一下。

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

【讨论】:

    【解决方案2】:

    您可以通过添加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 循环并跳过随机数量的文件。

    【讨论】:

    • while 循环是执行set(random.sample(all_files, 5)) 的一种非常低效的方式。最坏的情况,给定一个大/小all_files 和大数字,这永远不会终止。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-09
    • 2018-04-03
    • 2012-04-30
    • 1970-01-01
    • 1970-01-01
    • 2019-11-17
    相关资源
    最近更新 更多