views:

322

answers:

4

I have a list:

l = [['en', 60, 'command'],['sq', 34, 'komand']]

I want to search for 'komand' or 'sq' and get l[1] returned.

Can I somehow define my own matching function for list searches?

+1  A: 

You can do it this way:

def find(value, seq):
    for index, item in enumerate(seq):
        if value in item: 
            return index, item

In [10]: find('sq', [['en', 60, 'command'],['sq', 34, 'komand']])
Out[10]: (1, ['sq', 34, 'komand'])

Or if you want a general solution:

def find(fun, seq):
    for index, item in enumerate(seq):
        if fun(item): 
            return index, item

def contain(value):
    return lambda l: value in l

In [14]: find(contain('komand'), [['en', 60, 'command'],['sq', 34, 'komand']])
Out[14]: (1, ['sq', 34, 'komand'])
Nadia Alramli
A: 

If all you're trying to do is return the first list that contains a match for any of the values then this will work.

def search(inlist, matches):
    for li in inlist:
        for m in matches:
            if m in li:
                return li
    return None

>>> l = [['en', 60, 'command'],['sq', 34, 'komand']]
>>> search(l, ('sq', 'komand'))
['sq', 34, 'komand']
Rod Hyde
A: 

Yes:

has_oneof = lambda *patterns: lambda: values any(p in values for p in patterns)
result = itertools.ifilter(has_oneof('komand', 'sq'), l).next()
print result # prints ['sq', 34, 'komand']
anonymous
`result = (x for x in l if has_oneof('komand', 'sq')(x))` also works.
Omnifarious
no -- it makes 'result' a generator, not an element of l.
anonymous
Misplaced colon on first line.
Craig McQueen
+3  A: 

An expression like:

next(subl for subl in l if 'sq' in subl)

will give you exactly the sublist you're searching for (or raise StopIteration if there is no such sublist; if the latter behavior is not what you want, pass next a second argument [[e.g, [] or None, depending on what exactly you want!]] to return in that case). So, just use this result value, or assign it to whatever name you wish, and so forth.

Of course, you can easily dress this expression up into any kind of function you like, e.g.:

def gimmethesublist(thelist, anitem, adef=None):
    return next((subl for subl in thelist if anitem in subl), adef)

but if you're working with specific variables or values, coding the expression in-line may often be preferable.

Edit: if you want to search for multiple items in order to find a sublist containing any one (or more) of your items,

its = set(['blah', 'bluh'])
next(subl for subl in l if its.intersection(subl))

and if you want to find a sublist containing all of your items,

next(subl for subl in l if its.issubset(subl))
Alex Martelli
Wait, what? I've never thought of using next like that, I don't know if it's strange or really useful! In Python 2.5 terms this is `(<genexpr>).next()` ;-) (+1)
kaizer.se
@kaizer, in the 2.5 version it's less useful because it gives you no control over the "nothing satisfies the condition" case (so you usually have to add a try/except StopIteration which takes a lot of the elegance away). In 2.6 and later, thanks to `next` becoming a builtin, it's now an important and very useful idiom.
Alex Martelli
How might this technique be adapted to return the indices of the search term? Or would you have to fall back on a looping approach?
Virgil Disgr4ce