2009-11-03 21 views
9

Tengo una lista de nombres de archivos de bibliotecas que necesito filtrar contra expresiones regulares y luego extraigo el número de versión de aquellos que coinciden. Esta es la manera obvia de hacerlo:Filtrado y transformación de listas de 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)) 

que produce la siguiente lista:

['3.3.1', '3.2.0'] 

sin embargo siento que bucle no es muy 'estilo de Python' y sentir que debería ser posible reemplazar ' para 'bucle de arriba con un inteligente de una sola línea. Sugerencias?

Respuesta

19

¿Qué tal una lista de comprensión?

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

Usted puede hacer esto:

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

Yo no creo que sea muy fácil de leer, aunque ...

tal vez es más claro realiza en dos pasos:

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

realmente no necesita molestarse con expresiones regulares para su caso simple

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

Realice más comprobaciones para obtener las que tienen "puntos".

1

No hay nada que no sea pitónico con el uso de un bucle for estándar. Sin embargo, puede usar la función map() para generar una nueva lista basada en los resultados de una función ejecutada contra cada elemento de la lista.

0

¿Qué tal este:

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

Una forma de lo que podía pensar era combinar 'mapa' y la lista de comprensión.
La solución se ve de la siguiente manera:

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

Uno más de una sola línea sólo para mostrar otras formas (También he limpiado un poco de expresiones regulares):

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

Pero tenga en cuenta, que su la versión original es más legible que todas las sugerencias. ¿Vale la pena cambiar?

+1

Gracias por ambos 'findall' y 'sum'! En cuanto a la legibilidad, ya está acostumbrado a él con todos los algoritmos stl y boost :) –

+0

por alguna razón, este tiene mucho más sentido para mí que la respuesta aceptada/upvoted. –

Cuestiones relacionadas