2011-01-07 25 views
21

Po pierwsze, zamieszczam to, ponieważ gdy szukałem rozwiązania poniższego problemu, nie mogłem znaleźć jednego na stackoverflow. Mam nadzieję, że dodam trochę do bazy wiedzy.Jak sortować pliki numerycznie?

Potrzebuję przetworzyć niektóre pliki w katalogu i trzeba posortować pliki numerycznie. Znalazłem kilka przykładów na sortowaniu - konkretnie przy użyciu wzorca lambda - w wiki.python.org i kładę to razem:

#!env/python 
import re 

tiffFiles = """ayurveda_1.tif 
ayurveda_11.tif 
ayurveda_13.tif 
ayurveda_2.tif 
ayurveda_20.tif 
ayurveda_22.tif""".split('\n') 

numPattern = re.compile('_(\d{1,2})\.', re.IGNORECASE) 

tiffFiles.sort(cmp, key=lambda tFile: 
        int(numPattern.search(tFile).group(1))) 

print tiffFiles 

nadal jestem raczej nowy w Pythonie i chciałbym zapytać, czy istnieją społeczności Jakiekolwiek ulepszenia, które można wprowadzić: skrócenie kodu (usunięcie lambda), wydajność, styl/czytelność?

Dziękuję Zachary

+2

+1 za prawidłowy tytuł pytania. – systemovich

+4

Właściwym sposobem na zrobienie tego, co musisz zrobić, jest zadawanie pytania w pytaniu, a następnie dodawanie odpowiedzi w bicie odpowiedzi. Następnie usiądź wygodnie i poczekaj ... – paxdiablo

+0

@paxdiablo: Dziękuję za instrukcje ... Przeczytałem FAQ, aby upewnić się, że mogę odpowiedzieć, ale nie byłem całkiem pewien co do mechaniki. Zrobię to zaraz następnym razem. –

Odpowiedz

30

ten nazywany jest „naturalne sortowania” lub „ludzkie Sortowanie” (w przeciwieństwie do leksykograficznej sortowania, który jest domyślnie). Ned B wrote up a quick version of one.

import re 

def tryint(s): 
    try: 
     return int(s) 
    except: 
     return s 

def alphanum_key(s): 
    """ Turn a string into a list of string and number chunks. 
     "z23a" -> ["z", 23, "a"] 
    """ 
    return [ tryint(c) for c in re.split('([0-9]+)', s) ] 

def sort_nicely(l): 
    """ Sort the given list in the way that humans expect. 
    """ 
    l.sort(key=alphanum_key) 

Jest podobny do tego, co robisz, ale być może nieco bardziej uogólnione.

+1

Dziękuję, Daniel! Tego właśnie szukałem. Podążyłem za linkiem, który zawarłeś i w dół króliczej dziury, którą pojechałem ... weeee !!! Dowiedziałem się trochę o wydajności try/except i (oczywiście) wstępnym kompilowaniu wyrażeń regularnych. :) –

+0

Czy to zadziała, jeśli zwrócimy generator, a nie listę? –

+0

Niepoprawnie obsługuje ujemne liczby osadzone. – martineau

5

Jeśli używasz metody key= w swojej metodzie sortowania, nie powinieneś używać cmp, która została usunięta z najnowszych wersji Pythona. key należy utożsamiać z funkcją, która pobiera wpis jako dane wejściowe i zwraca obiekt, który będzie porównywany w kolejności, w jakiej ma być sortowana lista. Nie musi to być funkcja lambda i może być wyraźniejsza jako samodzielna funkcja. Również wyrażenia regularne mogą być powolne do oceny.

Można spróbować czegoś takiego do wyizolowania i powrócić część całkowitą nazwy pliku:

def getint(name): 
    basename = name.partition('.') 
    alpha, num = basename.split('_') 
    return int(num) 
tiffiles.sort(key=getint) 
+0

Dziękuję, Don. Naprawdę doceniam twoje wyjaśnienie: bardzo zrozumiałe. --Zachary –

+0

@Don O'Donnell Mam błąd _AttributeError: 'tuple' obiekt nie ma atrybutu 'split'_, więc trochę zmodyfikowałem twój kod: 'basename = name.partition ('. ')' Zmieniam z ' basename = name.split ('.') '(** Ważne! Działa tylko dla nazw plików bez kropek **) i' alpha, num = basename.split ('_') 'z' alpha, num = basename [0] .split ('_') 'W każdym razie, zrobiłeś mój dzień. Dzięki! – KnightWhoSayNi

0

wyników działowe w krotce

def getint(name): 
    (basename, part, ext) = name.partition('.') 
    (alpha, num) = basename.split('_') 
    return int(num) 
+0

Czy rzeczywiście tego spróbowałeś? '(a, b, c) = 'ayurveda_11.tif'.split ('. '), ValueError: do rozpakowania potrzeba więcej niż 2 wartości' –

5

wystarczy użyć:

tiffFiles.sort(key=lambda var:[int(x) if x.isdigit() else x for x in re.findall(r'[^0-9]|[0-9]+', var)]) 

jest szybszy niż użyj try/except.