2009-11-03 10 views
9

Mam listę nazw plików bibliotek, które należy filtrować względem wyrażenia regularnego, a następnie wypakowuję numer wersji od zgodnych. Jest oczywistym sposobem, aby to zrobić:Filtrowanie i transformacja list w języku Python

libs = ['libIce.so.33', 'libIce.so.3.3.1', 'libIce.so.32', 'libIce.so.3.2.0'] 
versions = [] 
regex = re.compile('libIce.so\.([0-9]+\.[0-9]+\.[0-9]+)') 
for l in libs: 
    m = regex.match(l) 
    if m: 
     versions.append(m.group(1)) 

która produkuje następującą listę:

['3.3.1', '3.2.0'] 

Jednak czuję, że pętla nie jest bardzo "w stylu Pythona i czuć powinno być możliwe do zastąpienia" dla 'pętli powyżej z jakąś inteligentną jedną linijką. Sugestie?

Odpowiedz

19

Co ze zrozumieniem listy?

In [5]: versions = [m.group(1) for m in [regex.match(lib) for lib in libs] if m] 
In [6]: versions 
Out[6]: ['3.3.1', '3.2.0'] 
5

Można to zrobić:

versions = [m.group(1) for m in [regex.match(l) for l in libs] if m] 

Nie sądzę, że to bardzo czytelny, choć ...

Może to wyraźniej zrobić w dwóch etapach:

matches = [regex.match(l) for l in line] 
versions = [m.group(1) for m in matches if m] 
0

Naprawdę nie musisz się martwić z regex dla twojego prostego przypadku

>>> libs = ['libIce.so.33', 'libIce.so.3.3.1', 'libIce.so.32', 'libIce.so.3.2.0'] 
>>> libs 
['libIce.so.33', 'libIce.so.3.3.1', 'libIce.so.32', 'libIce.so.3.2.0'] 
>>> for i in libs: 
... print i.split("so.") 
... 
['libIce.', '33'] 
['libIce.', '3.3.1'] 
['libIce.', '32'] 
['libIce.', '3.2.0'] 
>>> for i in libs: 
... print i.split("so.")[-1] 
... 
33 
3.3.1 
32 
3.2.0 
>>> 

Dalsze sprawdzanie, aby uzyskać te z "kropkami".

1

Nie ma nic, co nie byłoby pytonne na temat używania standardowego pętli. Można jednak użyć funkcji map(), aby wygenerować nową listę na podstawie wyników z funkcji uruchamianej dla każdego elementu na liście.

0

Jak o tym jednym:

import re 

def matches(regexp, list): 
    'Regexp, [str] -> Iterable(Match or None)' 
    return (regexp.match(s) for s in list) 

libs = ['libIce.so.33', 'libIce.so.3.3.1', 'libIce.so.32', 'libIce.so.3.2.0'] 
regexp = re.compile('libIce.so\.([0-9]+\.[0-9]+\.[0-9]+)') 
versions = [m.group(1) for m in matches(regexp, libs) if m is not None] 

>>> print versions 
['3.3.1', '3.2.0'] 
0

Jednym ze sposobów mogłem pomyśleć było połączenie „map” i lista zrozumieniem.
Rozwiązanie wygląda jak poniżej:

import re 
libs = ['libIce.so.33', 'libIce.so.3.3.1', 'libIce.so.32', 'libIce.so.3.2.0'] 
versions = [] 

regex = re.compile('libIce.so\.([0-9]+\.[0-9]+\.[0-9]+)') 

def match(s): 
    m = regex.match(s) 
    if m: 
     return m.group(1) 

versions = [x for x in map(match,libs) if x] 

8

Jeszcze jedno-liner żeby pokazać inne sposoby (Ja również czyszczone regexp nieco):

regex = re.compile(r'^libIce\.so\.([0-9]+\.[0-9]+\.[0-9]+)$') 
sum(map(regex.findall, libs), []) 

Ale uwaga, że ​​Twój Oryginalna wersja jest bardziej czytelna niż wszystkie sugestie. Czy warto to zmienić?

+1

Dzięki za "findall" i "sumę"! Jeśli chodzi o czytelność - przyzwyczaiłem się już do niego z wszystkimi algorytmami stl i boost :) –

+0

z jakiegoś powodu ten ma dla mnie dużo więcej sensu niż akceptowana/przegłosowana odpowiedź. –