2010-07-04 7 views
1

Supposons que j'ai une liste de noms de fichiers: [exia.gundam, dynames.gundam, kyrios.gundam, virtue.gundam] ou [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].Python: recherche de fichiers avec des extensions ou des extensions correspondantes avec des noms correspondants dans une liste

En une itération, j'aimerais avoir tous les fichiers * .gundam ou * .data, alors que de l'autre, je voudrais regrouper les fichiers exia. *. Quelle est la façon la plus simple de faire cela, en plus d'itérer dans la liste et de placer chaque élément dans un dictionnaire?

Voici ce que j'avais à l'esprit:

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 

Eh bien, en supposant que je dois l'utiliser, est-il un moyen simple d'inverser et avoir l'extension de fichier comme clé à la place du nom?

Répondre

2

Dans ma première version, il semble que j'ai mal interprété votre question. Donc, si j'ai bien compris, vous essayez de traiter une liste de fichiers afin que vous puissiez facilement accéder à tous les noms de fichiers avec une extension donnée, ou tous les noms de fichiers avec une base donnée ("base" étant la partie avant le période)?

Si tel est le cas, je recommanderais de cette façon:

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 
      )) 

Par exemple, étant donné la liste

>>> 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 
... ] 

cette fonction produirait

>>> 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']} 

Si vous vouliez indexer les noms de fichiers par extension à la place, une légère modification le fera pour vous:

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 
      )) 

La seule différence est dans la ligne keyfunc = ..., où je l'ai changé la clé de 0 à 1. Exemple:

>>> 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']} 

Si vous souhaitez obtenir ces deux groupes en même temps, cependant, Je pense qu'il vaudrait mieux éviter une compréhension de liste, car cela ne peut que les traiter d'une manière ou d'une autre, il ne peut pas construire deux dictionnaires différents à la fois.

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

Je suis très bien avec itérer dans la liste, mais je me demandais s'il y avait une solution plus générique (et simple). Donc, si je devais changer le format de .gundam en .flag, je pourrais utiliser le même code. Je pourrais itérer la liste et les ajouter manuellement à une carte pour voir ce qui correspond à la première ou deuxième partie du nom de fichier, mais cela entraînerait beaucoup plus de code. –

+0

OK, je pense que peut-être mon dernier exemple de code dans la version éditée est plus ce que vous cherchez. Si toutes vos conditions spécifient le début ou la fin du nom de fichier, vous pouvez utiliser les méthodes de chaîne 'startswith' et' endswith' au lieu des expressions régulières, ce qui peut économiser un peu de temps de calcul, mais le code sera plus long (mais Je pourrais éditer de cette façon aussi, si vous voulez). –

+0

@Setsuna: Eh bien, je pense que vous pouvez utiliser os.listdir (chemin) itérer sur le répertoire et obtenir toutes les extensions disponibles, puis, avec cette liste, vous pouvez les regrouper comme David a dit. –

0

Je ne suis pas sûr si je suis tout à fait ce que vous cherchez à faire, mais si je comprends bien quelque chose comme cela pourrait fonctionner:

from collections import defaultdict 
files_by_extension = defaultdict(list) 

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

Cela crée une clé de hachage par extension de fichier et le remplissage en itérant dans la liste en un seul passage.

0

Supposons par exemple que vous voulez à la suite une liste de listes de noms de fichiers, regroupés soit par l'extension ou rootname:

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)] 

Maintenant files_grouped_by(filenames, False) retournera la liste des listes de regroupement par rootname, alors que si le second argument est Vrai ou absent, le regroupement sera par extension.

Si vous voulez plutôt un dict, les clés étant soit rootnames ou extensions, et les valeurs des listes de noms de fichiers, l'approche est assez similaire correspondant:

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)] 
Questions connexes