Уникальный генератор случайных файлов - PullRequest
0 голосов
/ 07 января 2020

У меня есть каталог с большим количеством файлов. Я не хочу хранить все имена файлов в памяти, но я хочу случайным образом получить подмножество этих файлов, используя генератор.

Я могу сделать это, используя информацию из поста " Лучший способ выбрать случайный файл из каталога ", но я хотел бы убедиться, что мой генератор никогда не вернет тот же файл дважды. Поэтому, в конце концов, после запуска генератора (который будет возвращать пакеты), я перебрал бы весь список файлов в каталоге.

Методы, которые я могу придумать, по-прежнему создают список файлов для сравнения (Создать список уже использованных имен файлов и возвращаются, если их нет в списке), и для их выполнения потребуется больше времени, чем больше результатов выдает генератор.

Есть ли способ, если я создаю массив чисел, равный количеству файлов в каталоге, чтобы при случайном извлечении значения из массива я мог получить файл в этой позиции? (Я думаю, что это заняло бы значительно меньше памяти, чем массив строк)

Из текущих комментариев у меня есть следующий код:

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

Ответы [ 2 ]

1 голос
/ 07 января 2020

Я упомянул этот подход в комментариях, но я не знаю, правильно ли я его объяснил, поэтому я уточню здесь.

Вы можете использовать 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)

В любом случае генератор будет go просматривать весь список файлов в каталоге , никогда не повторяясь в будущем, пока список файлов не будет исчерпан. Пример вывода:

b
c
f
e
d
a

Оба подхода имеют O (N) время выполнения. Другими словами, каждое дополнительное полученное значение занимает столько же времени, сколько и предыдущие полученные значения. Это частично объясняется тем фактом, что функция генератора не разбивает список и не манипулирует каким-либо иным образом списком в пределах for l oop.

0 голосов
/ 07 января 2020

Вы можете отрегулировать решение на основе упомянутого вопроса, добавив set и проверьте его длину. Вот пример:

import os
import random

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

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

Что касается потребления памяти, вам все равно нужно загрузить весь список файлов, если вы не используете какой-либо шаблон имени файла, чтобы избежать вывода списка, и l oop это с itertools.cycle и пропустить случайное количество файлов.

...