Partida parcial de tuplas

Tengo una tupla de tuplas y una tupla. Me interesa saber qué elementos de la primera tupla coinciden con la segunda tupla (si corresponde), considerando también las coincidencias parciales.

Esta es una función de filtro para demostrar lo que quiero decir.

def f(repo): pattern = (None, None, '1.3') for idx, item in enumerate(pattern): if item != None and item != repo[idx]: return False return True >>> repo = (('framework', 'django', '1.3'), ('cms', 'fein', '1.3'), ('cms', 'django-cms', '2.2')) >>> filter(f, repo) (('framework', 'django', '1.3'), ('cms', 'fein', '1.3')) 

El filtro es inútil en esta forma porque el patrón no puede proporcionarse externamente como un argumento (quiero usar la misma función para verificar diferentes entradas). ¿Hay una manera de solucionar esto?

Y, ¿cuál podría ser otro algoritmo para adoptar para un mejor enfoque del problema original?

Puede utilizar un cierre para enlazar el patrón en la función:

 def matcher(pattern): def f(repo): return all(p is None or r == p for r, p in zip(repo, pattern)) return f >>> repo = (('framework', 'django', '1.3'), ('cms', 'fein', '1.3'), ('cms', 'django-cms', '2.2')) >>> pattern = (None, None, '1.3') >>> filter(matcher(pattern), repo) (('framework', 'django', '1.3'), ('cms', 'fein', '1.3')) 

También he proporcionado una expresión diferente para comparar las tuplas.

¿Por qué no usas el filter incorporado?

 >>> filter(lambda x: x[2] == '1.3', repo) <<< (('framework', 'django', '1.3'), ('cms', 'fein', '1.3')) 

... o una lista de comprensión :

 >>> [x for x in repo if x[2] == '1.3'] <<< [('framework', 'django', '1.3'), ('cms', 'fein', '1.3')] 

Si quisieras envolverlo en una función:

 types = {'desc': 0, 'name': 1, 'version': 2} def repo_filter(type, critera, repo=repo, types=types): return [x for x in repo if x[types[type]] == critera] >>> repo_filter('version', '1.3') <<< [('framework', 'django', '1.3'), ('cms', 'fein', '1.3')] 
 In [43]: [r for r in repo if all((p is None or q==p) for q,p in zip(r,pattern))] Out[43]: [('framework', 'django', '1.3'), ('cms', 'fein', '1.3')] 
 def my_filter(pattern, repo): def f pattern = (None, None, '1.3') for idx, item in enumerate(pattern): if item != None and item != repo[idx]: return False return True return filter(f, repo) my_filter((None, None, '1.3'), repo) 

Qué pasa:

 def f(repo, pattern=None): if not pattern: pattern = (None, None, '1.3') for idx, item in enumerate(pattern): if item and item != repo[idx]: return False return True repo = (('framework', 'django', '1.3'), ('cms', 'fein', '1.3'), ('cms', 'django-cms', '2.2')) [x for x in repo if f(x)] >>>[('framework', 'django', '1.3'), ('cms', 'fein', '1.3')] [x for x in repo if f(x, ('cms',None, None))] >>> [('cms', 'fein', '1.3'), ('cms', 'django-cms', '2.2')] 

Puedes usar la siguiente expresión:

 repo = (('framework', 'django', '1.3'), ('cms', 'fein', '1.3'), ('cms', 'django-cms', '2.2')) p = (None, None, '1.3') matches = [i for i in repo if i[0]==p[0] or i[1]==p[1] or i[2]==p[2]] 

o utilizar el cierre, como este:

 def matcher(pattern): def pattern_matcher(repo): for idx, item in enumerate(pattern): if item is not None and item != repo[idx]: return False return True return pattern_matcher 

y luego se puede invocar así:

 filter(matcher(pattern), repo)