Python: поиск файлов с соответствующими расширениями или расширениями с соответствующими именами в списке - PullRequest
1 голос
/ 04 июля 2010

Предположим, у меня есть список имен файлов: [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

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

Ответы [ 3 ]

2 голосов
/ 04 июля 2010

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

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

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 голосов
/ 04 июля 2010

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

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) вернет список списков, сгруппированных по корневому имени, в то время как если второй аргумент равен 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 голосов
/ 04 июля 2010

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

from collections import defaultdict
files_by_extension = defaultdict(list)

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

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

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