【问题标题】:How to quickly pick a random file from a folder-tree?如何从文件夹树中快速选择随机文件?
【发布时间】:2019-10-15 17:46:13
【问题描述】:

我正在尝试从文件夹树中选择一个随机文件,从固定路径开始并在所有子文件夹(或所选文件夹本身)中递归“搜索”。

我的想法是:制作文件列表,计算文件数量,在此范围内选择一个随机数,然后在该索引处选择文件。

这是我的代码:

// create list of all files
std::vector<std::string> paths;

for (const auto &entry : std::filesystem::recursive_directory_iterator(mPathDirectory)) {
    if (!std::filesystem::is_directory(entry)) {
        paths.push_back(entry.path().string());
    }
}

// pick random file
size_t numberOfFiles = paths.size();
int indexRandomFile = (int)round(rescale(random::uniform(), 0.0, 1.0, 0, numberOfFiles - 1));

return paths[indexRandomFile];

还有O3,考虑到我有一个巨大的文件列表并且我在一个“音频”应用程序中(应该更快),它非常慢。

你有什么更聪明的想法吗?像O(1)这样的东西? :P

【问题讨论】:

    标签: c++ performance file random


    【解决方案1】:

    可以使用reservoir sampling 技术以这种方式随机选择文件。对于每个文件,以 1/N 的几率选择它,其中 N 是您到目前为止找到的文件数,包括刚刚找到的文件。随机文件就是最后一个以这种方式选择的文件。

    另请参阅this question,了解从文本文件中选择随机行的类似任务;通常,只要事先不知道可供选择的项目数量,就会应用水库抽样。


    以下解释了水库采样的工作原理:

    1. 将 N 设置为 1。
    2. 将 ChosenFile 设置为 null。
    3. 对于每个文件:
      • 如果是random::uniform() &lt; 1.0 / N,请将 ChosenFile 设置为文件名。
      • N 加 1。

    现在,ChosenFile 是随机选择的文件名。


    以您问题中的代码为例,这里是水库采样的实施方式。请注意,不再将文件存储在列表中。另请注意,此代码未经测试。

    // store randomly chosen file
    std::string path;
    size_t n = 1;
    
    for (const auto &entry: std::filesystem::recursive_directory_iterator(mPathDirectory)) {
        if (!std::filesystem::is_directory(entry)) {
            if (random::uniform() < 1.0 / n) {
               path = entry.path().string();
            }
            n++;
        }
    }
    
    return path;
    

    【讨论】:

    • 但是如何从数字/索引中选择文件?我需要一个列表开始...
    • 您的问题(在您的问题帖子中)没有提到从 its index 中选择随机文件(除了作为从目录中选择随机文件的一种方式) .水库采样不需要您存储在随机选择其中一个文件的过程中找到的所有文件的名称。无论如何,我将编辑此答案以更好地解释水库采样的工作原理。
    • 是“for each”文件的问题。迭代大量文件会使任务变慢。那是我的问题...
    • 您是说recursive_directory_iterator 本身对于您的目的来说太慢了吗?您是否注意到在向量中存储和不存储每个文件名在运行时间上有显着差异?
    • 你会在文件名上存储什么?指针?不确定...
    【解决方案2】:

    如果您对文件夹结构一无所知,则必须递归到它以找出有多少项目。没有 O(1) 解。

    但“应用程序”只需要感觉快,即通常只有对响应能力的感知才重要。为此,在第一次开始时,您可以使用启发式方法,例如以一定的概率递归到 some 子文件夹,直到找到 a 文件。它不会是一律随机的,而是会从用户的角度相对任意地选择。

    同时您可以真正递归到文件夹并建立一个缓存,而最初选择的文件已经在播放。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多