2009-11-03 1 views
9

У меня есть список имен файлов библиотек, которые мне нужно отфильтровать от регулярного выражения, а затем извлечь номер версии из тех, которые соответствуют. Это очевидный способ сделать это:Фильтрация и преобразование списков 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)) 

Это приводит следующий список:

['3.3.1', '3.2.0'] 

Тем не менее, я чувствую, что петля не очень «стиль Python» и чувствовать, что должно быть возможно заменить ' для 'цикла выше с помощью некоторого умного однострочного. Предложения?

ответ

19

Как насчет понимания списка?

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

Вы можете сделать это:

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

Я не думаю, что это очень читаемым, хотя ...

Может быть, это понятнее делается в два этапа:

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

вам не нужно беспокоиться о регулярном выражении для вашего простого случая

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

Дальнейшая проверка, чтобы получить те, у которых есть «точки».

1

Нет ничего, что не является питоническим в использовании стандарта для цикла. Однако вы можете использовать функцию map() для создания нового списка на основе результатов от функции, выполняемой против каждого элемента в списке.

0

Как об этом один:

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

Один из способов я мог думать только о том, чтобы объединить «карта» и список понимание.
Решение выглядит так, как показано ниже:

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

еще один один лайнер, чтобы показать другие способы (я также очищено регулярное выражение немного):

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

Но обратите внимание, что ваш оригинальная версия более читаема, чем все предложения. Стоит ли меняться?

+1

Спасибо за «поиск» и «сумму»! Что касается читаемости - уже привык к этому со всеми алгоритмами stl и boost :) –

+0

по какой-то причине это имеет для меня гораздо больше смысла, чем принятый/поддержанный ответ. –