Tuples partial match

∥☆過路亽.° 提交于 2019-12-11 00:38:13

问题


I have a tuple of tuples and a tuple. I'm interested to know which elements of the first tuple match the second tuple (if any), considering partial matches too.

This is a filter function to demonstrate what I mean.

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

The filter is useless in this form because the pattern can't be provided externally as an argument (I want to use the same function to check different inputs). Is there a way to fix this?

And, what could be another algorithm to embrace for a better approach to the original problem?


回答1:


You can use a closure to bind the pattern into the function:

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

I've also provided a different expression for comparing the tuples.




回答2:


Why don't you use the built-in filter:

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

...or a list comprehension:

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

If you wanted to wrap it up into a function:

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')]



回答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')]



回答4:


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)



回答5:


What about:

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')]



回答6:


You can use the following expression:

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

or use closure, such as this:

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

and then can be invoked like this:

filter(matcher(pattern), repo)


来源:https://stackoverflow.com/questions/7175736/tuples-partial-match

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!