在大目录中查找随机对

时间:2016-08-23 20:19:09

标签: python performance io

我有~~ 500万个csv文件存储在〜100.000个文件夹中。每个文件夹包含大致相同数量的文件,并且文件夹中始终存在偶数个文件。我需要找到所有这些文件的路径,并按照一个奇怪的顺序将它们加载到一个列表中进行统计建模项目。

特别是,我需要坚持以下内容:

  • 唯一性:每个文件只能在列表中
  • 对:每个文件必须位于同一文件夹中的另一个文件的旁边(如果由于随机性,它可以紧挨着两个文件)
  • 随机性:任何两个文件没有"配对的概率"彼此相邻应该是相同的(即,它不会只是迭代所有文件)

我在下面创建了一个示例。

文件

Folder_1
- File_A
- File_B
- File_C
- File_D
Folder_2
- File_E
- File_F
- File_G
- File_H

良好的结果(随机,但坚持对的规则)

paths = ['Folder_1/File_A', 'Folder_1/File_D', 'Folder_2/File_G',  'Folder_2/File_F',  'Folder_2/File_E', 'Folder_2/File_H', 'Folder_1/File_C', 'Folder_1/File_B']

一个简单的方法可能是"选择一个随机文件夹,在该文件夹中选择一个随机文件,并在文件夹中选择一个随机对。将这些选择保存在列表中以避免再次被选中。重复。&#34 ;.但是,这需要太长时间。你能推荐一个很好的策略来创建这个列表吗?如果需要,可以稍微放宽随机性要求。

2 个答案:

答案 0 :(得分:1)

确保一切随机的一种方法是使用random.shuffle,这会在列表中随机播放。这样你可以简单地将每个项目与其邻居配对,安全地知道配对是随机的。为了获得类似于您的示例的结果,您可以随后对结果列表进行随机化和展平。这是一个例子:

from random import shuffle

# generate some sample directory names
ls = [[]] * 5
i = 0
while i < len(ls):
    ls[i] = [str(i) + chr(j) for j in range(97,101)]
    i += 1

# shuffle files within each directory
pairs = []
for l in ls:
    shuffle(l)
    pairs += list(zip(l[1::2], l[::2]))

# shuffle and flatten the list of pairs
shuffle(pairs)
flat = [item for sublist in pairs for item in sublist]    
print(flat)

答案 1 :(得分:1)

最好的策略是在线程的帮助下分而治之。您希望尽快将文件名加载到内存中以便最快完成。

第一步是为文件夹名称创建一个队列,为每个文件夹中的文件列表创建另一个队列。类似的东西:

folders = queue.Queue()
files = queue.Queue()

队列很像列表,只能在不同线程之间安全共享。使用线程一次处理多个文件夹将加快处理时间。

创建一个函数,它将获取每个文件夹的路径,然后存储每个路径“folders”队列。

folderPaths = getFolderPaths()
for path in folderPaths:
    folders.put(path)

最终你会得到一个包含所有文件夹路径的队列(例如[“文件夹A”,“文件夹B”,...])

为将遍历文件夹中所有文件的线程创建一个worker函数,并将每个文件的名称存储在列表中。一般的想法是:

def threadJob():
    while True:
        folderPath = folders.get()
        if folderPath is None:
           break
        fileNames = getFilesInFolder(folderPath)
        files.put(fileNames)

这里“getFilesInFolder()”是一个函数,它接受一个path参数并返回该文件夹中所有文件的列表。

当所有线程都完成时,“files”应该包含每个文件夹的文件列表。现在,您需要将队列清空为常规列表。

fileList = []
file = files.get()
while file not None:
    fileList.append(file)
    file = files.get()

现在您有一个列表列表。随机化每个列表以随机化文件顺序:

for files in fileList:
    random.shuffle(files)

现在您可以创建最终列表(statList)并弹出随机选择的子列表中的文件对,直到所有文件都被追加为止:

statList = []

while len(finalFileList > 0):
    index = random.randrange(len(fileList))
    if len(fileList[index]) == 0:
        fileList.pop(index)
    else:
        statList.append(fileList.pop())
        statList.append(fileList.pop())

不能保证这会很快,但这是我能想到的最快的方法。

如果感兴趣,请访问有关队列和线程的更多信息:

https://docs.python.org/3/library/queue.html

http://www.tutorialspoint.com/python3/python_multithreading.htm