2012-02-27 12 views
5

Diciamo che ho una lista di filefile ordinamento in una lista

files = ['s1.txt', 'ai1.txt', 's2.txt', 'ai3.txt'] 

e ho bisogno di ordinarli in sotto-liste in base al largo di loro in modo che

files = [['s1.txt', 'ai1.txt'], ['s2.txt'], ['ai3.txt']] 

Potrei scrivere un sacco di loop, tuttavia mi chiedo se c'è un modo migliore per farlo?

+1

l'elenco dei file già ordinati secondo il numero, come sembra essere nell'esempio? –

+0

no sfortunatamente. – John

+4

Quello che vuoi è * il raggruppamento *, non * l'ordinamento *. –

risposta

6

Qui è un esempio funzionante completo basato su defaultdict:

import re 
from collections import defaultdict 

files = ['s1.txt', 'ai1.txt', 's2.txt', 'ai3.txt'] 

def get_key(fname): 
    return int(re.findall(r'\d+', fname)[0]) 

d = defaultdict(list) 
for f in files: 
    d[get_key(f)].append(f) 

out = [d[k] for k in sorted(d.keys())] 
print(out) 

Questo produce:

[['s1.txt', 'ai1.txt'], ['s2.txt'], ['ai3.txt']] 
+0

Davvero un'ottima risposta, ha funzionato molto bene per quello che stavo facendo. – John

4
import itertools 
import re 

r_number = re.compile("^.*([0-9]+).*$") 

def key_for_filename(filename): 
    # Edit: This doesn't check for missing numbers. 
    return r_number.match(filename).group(1) 

grouped = [list(v) for k, v in 
      itertools.groupby(sorted(files, key=key_for_filename), 
          key_for_filename)] 
+0

+1 Vorrei anche mettere una funzione di generazione di chiavi di esempio, come 'lambda x: re.sub ('[^ 0-9]', '', x)'. –

+3

Questa risposta presuppone erroneamente che l'elenco sia già ordinato per numero. –

+0

Nella domanda è :) –

1

In primo luogo, scrivere una funzione che estrae il numero da un nome di file: (. Si noti che questa funzione errore se c'è nessun numero a tutti nel nome)

def file_number(name): 
    return re.search(r"\d+", "s1.txt").group(0) 

Ordinare l'elenco di utilizzare questa funzione come una chiave:

files.sort(key=file_number) 

Gruppo da questa chiave utilizzando itertools.groupby():

for number, group in itertools.groupby(files, file_number): 
    # whatever 
0

Qualcosa di simile potrebbe funzionare ..

#!/usr/bin/python 

from itertools import groupby 
import re 
import pprint 

def findGroup(record): 
    return re.match(".*?(\d+).txt$", record).group(1) 

files = [ 's1.txt', 'ai1.txt', 's2.txt', 'ai3.txt', 'foo1.txt', 'foo54.txt' ] 

results = {} 
for k,g in groupby(files, findGroup): 
    if not results.has_key(k): 
     results[k] = [] 
    results[k].append([x for x in g]) 

pprint.pprint(results) 

Nota, quella depen ding l'ordine, si otterrà liste all'interno di elenchi, ma è possibile comprimere quelli abbastanza facilmente ..

uscita Esempio:

{'1': [['s1.txt', 'ai1.txt'], ['foo1.txt']], 
'2': [['s2.txt']], 
'3': [['ai3.txt']], 
'54': [['foo54.txt']]} 
Problemi correlati