遍历字典键引用的未知数量列表以比较每个列表内的值
我最近开始写一个小脚本,目的是输入一个装满文件的文件夹(这里是电子书,格式包括epub、mobi、djvu和pdf),找到几乎所有方面都相同但扩展名不同的文件(比如同一本书的多种电子书格式),为这本书创建一个文件夹,并把文件放到这个文件夹里,以便于导入到Calibre中。
我决定用一种数据结构来存储这些文件,具体是一个字典,里面的每个键是文件的扩展名,值是一个列表,列表里放的是对应扩展名的文件名。如果这样说不太清楚,这就是我构建的结构示例:{文件扩展名:[文件名,文件名,...], 文件扩展名:[文件名,文件名,...], ...}
我遇到的问题是,为了匹配每个列表中的单独值,我不能仅仅用嵌套的for循环,因为我并不确定会有多少个键。
我是在Windows 64位环境下用Python 2.7.2写这个脚本的。
代码:
import glob
workDirectory = 'E:\Some eBooks'
fileExtensions = ['mobi','epub','pdf','djvu']
# Create an appropriate holding structure for our results {fileExtension:[fileName,fileName,...]}
foundFiles = dict.fromkeys(fileExtensions,[])
for ext in fileExtensions:
print('Looking for ' + ext + ' files in ' + workDirectory)
for file in glob.glob(workDirectory + '/*.' + ext):
foundFiles[ext].append(file)
我知道我可以静态地写循环,假设会有四个键来自fileExtensions
,但在后面一旦代码正常工作后,我希望能通过argparse让代码接受任意数量的fileExtensions
。
我想我最核心的问题是,如何在同一次迭代中,使用可变数量的字典键来循环多个列表?如果我知道每个列表的固定名称,并且每个列表都有相同数量的值,我会这样做:
for one, two, three, four in list1 list2 list3 list4:
......
但我知道这样做行不通,因为我并不知道我会循环多少个列表,而且我也知道每个列表所需的迭代次数不会相同。
我有种不好的预感,觉得自己把这个问题想得太复杂,搞得自己有点困惑。也许用一组嵌套列表会有效,但我总觉得可以用更简单的方法来实现。
如果有任何建议,我会非常感激。
3 个回答
为什么不直接用一个简单的列表,把你所有文件的路径都放在里面,然后用正则表达式(regex)来遍历这个列表,找到所有和你当前文件名相同的文件呢?
我会把找到的文件按名字存起来,这样一读就能把它们分组。比如这样:
foundFiles = {}
for ext in fileExtensions:
print('Looking for ' + ext + ' files in ' + workDirectory)
for file in glob.glob(workDirectory + '/*.' + ext):
basename = os.path.basename(os.path.splitext(file)[0])
grouped_files = foundFiles.get(basename, [])
grouped_files.append(file)
foundFiles[basename] = grouped_files
现在你有了一个叫 foundFiles
的东西,其中的键是文件的基本名字,值是文件的路径。举个例子:
{ 'batman': ['/some/path/batman.pdf', '/other/path/batman.mobi']
'superman': ['/some/path/superman.epub', '/other/path/superman.djvu'] }
为了遍历 workDirectory
这个文件夹里的所有文件,并收集所有带有 fileExtensions
后缀的文件:
import os
from collections import defaultdict
fileExtensions = ('.mobi', '.epub', '.pdf', '.djvu')
foundFiles = defaultdict(list)
for dirpath, dirs, files in os.walk(workDirectory):
for file in files:
if file.endswith(fileExtensions):
basename = os.path.splitext(file)[0]
foundFiles[basename].append(os.path.join(dirpath, file))
这里的 foundFiles
格式和 @jterrace 的回答 是一样的:
{
"batman": [
"/some/path/batman.pdf",
"/other/path/batman.mobi"
],
"superman": [
"/some/path/superman.epub",
"/other/path/superman.djvu"
]
}