Перебор по неизвестному количеству списков, на которые ссылается ключ словаря, чтобы позволить сравнение значений в каждом списке - PullRequest
2 голосов
/ 16 декабря 2011

Недавно я начал писать небольшой сценарий, в котором я собираюсь ввести каталог, полный файлов (в данном случае электронные книги epub, mobi, djvu, pdf), найти файлы, которые совпадают друг с другом (почти) во всех отношениях, кроме расширения (например,Несколько форматов файлов электронных книг для одной и той же «книги»), создайте каталог для этой «книги» и поместите файлы в каталог для легкого импорта в Calibre.

Я выбрал структуру данных для файлов, которая быладиктат списков, где имена файлов группируются по расширению (ключу) в список (значение).Если это неясно, это мой макет структуры: {fileExtension: [fileName, fileName, ...], fileExtension: [fileName, fileName, ...] ...}

Проблема, с которой я столкнулся, состоит в том, чтобы сопоставить отдельные значения в каждом списке, сгруппированные по ключу. Я не могу просто использовать гнездо для циклов for, если я не обязательно знаю, сколько ключей у меня будет.

Запись этого в Python 2.7.2 в 64-битной среде Windows

Код:

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 будут созданы четыре ключа, но позже, когда все заработает, я бы хотел, чтобы код принял произвольное число значений до fileExtensions через argparse.

Я думаю, мое ядроВопрос в том, как зациклить несколько списков, используя переменное количество ключей словаря в качестве ссылки на списки в одной и той же итерации?Если бы я знал статические имена каждого списка и чтобы у каждого из них было одинаковое количество значений, я бы сделал:

for one, two, three, four in list1 list2 list3 list4:
    ......

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

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

Буду признателен за любые предложения о том, как действовать дальше.

Ответы [ 3 ]

2 голосов
/ 16 декабря 2011

Вместо этого я бы сохранял найденные файлы по их именам, чтобы они сгруппировались, как только вы их прочитаете. Как это:

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'] }
1 голос
/ 16 декабря 2011

Чтобы просмотреть дерево каталогов 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's answer :

{
    "batman": [
        "/some/path/batman.pdf", 
        "/other/path/batman.mobi"
    ], 
    "superman": [
        "/some/path/superman.epub", 
        "/other/path/superman.djvu"
    ]
}
0 голосов
/ 16 декабря 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...