Python: поиск файлов с соответствующими расширениями или расширениями с соответствующими именами в списке

1

Предположим, у меня есть список имен файлов: [exia.gundam, dynames.gundam, kyrios.gundam, virtue.gundam] или [exia.frame, exia.head, exia.swords, exia.legs, exia.arms, exia.pilot, exia.gn_drive, lockon_stratos.data, tieria_erde.data, ribbons_almark.data, otherstuff.dada].

На одной итерации я хотел бы иметь все файлы *.gundam или *.data, тогда как с другой стороны я хотел бы сгруппировать файлы exia. *. Какой самый простой способ сделать это, помимо повторения списка и размещения каждого элемента в словаре?

Вот что я имел в виду:

def matching_names(files):
    '''
    extracts files with repeated names from a list

    Keyword arguments:
    files - list of filenames

    Returns: Dictionary
    '''

    nameDict = {}
    for file in files:
        filename = file.partition('.')
        if filename[0] not in nameDict:
            nameDict[filename[0]] = []
        nameDict[filename[0]].append(filename[2])

    matchingDict = {}
    for key in nameDict.keys():
        if len(nameDict[key]) > 1:
            matchingDict[key] = nameDict[key] 
    return matchingDict

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

Теги:
string

3 ответа

2
Лучший ответ

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

Если в этом случае я бы рекомендовал этот способ:

from itertools import groupby

def group_by_name(filenames):
    '''Puts the filenames in the given iterable into a dictionary where
    the key is the first component of the filename and the value is
    a list of the filenames with that component.'''
    keyfunc = lambda f: f.split('.', 1)[0]
    return dict( (k, list(g)) for k,g in groupby(
               sorted(filenames, key=keyfunc), key=keyfunc
           ) )

Например, учитывая список

>>> test_data = [
...   exia.frame, exia.head, exia.swords, exia.legs,
...   exia.arms, exia.pilot, exia.gn_drive, lockon_stratos.data,
...   tieria_erde.data, ribbons_almark.data, otherstuff.dada
... ]

эта функция создаст

>>> group_by_name(test_data)
{'exia': ['exia.arms', 'exia.frame', 'exia.gn_drive', 'exia.head',
          'exia.legs', 'exia.pilot', 'exia.swords'],
 'lockon_stratos': ['lockon_stratos.data'],
 'otherstuff': ['otherstuff.dada'],
 'ribbons_almark': ['ribbons_almark.data'],
 'tieria_erde': ['tieria_erde.data']}

Если вы хотите индексировать имена файлов по расширению, небольшая модификация сделает это для вас:

def group_by_extension(filenames):
    '''Puts the filenames in the given iterable into a dictionary where
    the key is the last component of the filename and the value is
    a list of the filenames with that extension.'''
    keyfunc = lambda f: f.split('.', 1)[1]
    return dict( (k, list(g)) for k,g in groupby(
               sorted(filenames, key=keyfunc), key=keyfunc
           ) )

Единственное различие заключается в строке keyfunc = ..., где я изменил ключ от 0 до 1. Пример:

>>> group_by_extension(test_data)
{'arms': ['exia.arms'],
 'dada': ['otherstuff.dada'],
 'data': ['lockon_stratos.data', 'ribbons_almark.data', 'tieria_erde.data'],
 'frame': ['exia.frame'],
 'gn_drive': ['exia.gn_drive'],
 'head': ['exia.head'],
 'legs': ['exia.legs'],
 'pilot': ['exia.pilot'],
 'swords': ['exia.swords']}

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

from collections import defaultdict
def group_by_both(filenames):
    '''Puts the filenames in the given iterable into two dictionaries,
    where in the first, the key is the first component of the filename,
    and in the second, the key is the last component of the filename.
    The values in each dictionary are lists of the filenames with that
    base or extension.'''
    by_name = defaultdict(list)
    by_ext = defaultdict(list)
    for f in filenames:
        name, ext = f.split('.', 1)
        by_name[name] += [f]
        by_ext[ext] += [f]
    return by_name, by_ext
  • 0
    Я в порядке итерации по списку, но мне было интересно, есть ли более общее (и простое) решение. Так что, если бы я изменил формат с .gundam на .flag, я мог бы использовать тот же код. Я мог бы перебрать список и вручную добавить их на карту, чтобы увидеть, какие совпадения соответствуют первой или второй части имени файла, но это привело бы к гораздо большему количеству кода.
  • 0
    Хорошо, я думаю, что мой последний пример кода в отредактированной версии - это больше, чем вы ищете. Если все ваши условия указывают начало или конец имени файла, вы можете использовать строковые методы startswith и endswith строки вместо регулярных выражений, что может сэкономить немного времени на вычисления, но код будет длиннее (но я мог бы отредактировать это кстати тоже, если хотите).
Показать ещё 3 комментария
0

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

import os.path
import itertools as it

def files_grouped_by(filenames, use_extension=True):
    def ky(fn): return os.path.splitext(fn)[use_extension]
    return [list(g) for _, g in it.groupby(sorted(filenames, key=ky), ky)]

Теперь files_grouped_by(filenames, False) вернет список группировок списков по имени root, а если второй аргумент True или отсутствует, группировка будет выполняться по расширению.

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

import os.path
import itertools as it

def dict_files_grouped_by(filenames, use_extension=True):
    def ky(fn): return os.path.splitext(fn)[use_extension]
    return dict((k, list(g)) 
                for k, g in it.groupby(sorted(filenames, key=ky), ky)]
0

Я не уверен, что полностью получаю то, что вы хотите сделать, но если я правильно понял, что-то вроде этого может работать:

from collections import defaultdict
files_by_extension = defaultdict(list)

for f in files:
    files_by_extension[ f.split('.')[1] ].append(f)

Это создает хеш-ключ с расширением файла и заполняет его, итерируя через список за один проход.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню