tags:

views:

256

answers:

3

I want to search a tuple of tuples for a particular string and return the index of the parent tuple. I seem to run into variations of this kind of search frequently.

What is the most pythonic way to do this?

I.E:

derp = (('Cat','Pet'),('Dog','Pet'),('Spock','Vulcan'))
i = None
for index, item in enumerate(derp):
    if item[0] == 'Spock':
         i = index
         break
>>>print i
2

I could generalize this into a small utility function that takes an iterable, an index (I've hard coded 0 in the example) and a search value. It does the trick but I've got this notion that there's probably a one-liner for it ;)

I.E:

def pluck(iterable, key, value):
    for index, item in enumerate(iterable):
        if item[key] == value:
             return index
    return None
A: 

Lambdas are fun!

return reduce(
    lambda x,(i,(a,b)): i,
    filter(
        lambda (i,(a,b)): a == "Spock",
        enumerate(depr)
    ),
    None
)
ron
The problems with `filter()` are: (1) it will always search the whole list and (2) it will return a list of matches, rather then any match's index.
Max Shawabkeh
(1) true (2) can be worked around with map or reduce (see edited post)
ron
By the way, the original code posted is fine and doesn't have this "flaw". Loving lambdas is a personal trait ;)
ron
maybe i'm missing something: what's wrong with the pluck function defined by Koobz? IMHO is more readable, more generic and with better performances: `100000 loops, best of 3: 1.37 usec per loop` for the function defined by Koobz and `100000 loops, best of 3: 5.82 usec per loop` for the yours.
mg
Unpythonic, long, inefficient, and unreadable.
Paul Hankin
The functional way to write this is `itertools.dropwhile(lambda a: a[0] != 'Spock', derp).next()`
Paul Hankin
LOL maybe there's a lesson to be learned here. Darn Python keeps me second guessing myself ;)Ron's example did lead me in some interesting directions. Haven't played with filter yet.What happened to the whole 'one obvious way to do it' thing ;)
Koobz
The pluck function defined by Koobz is perfectly fine. Its clean, legible and pythonic.
HS
@Paul I would not say unpythonic once all elements are well in python. Unreadable is subjective, I can read it fine for example. But for the itertools thing, thanks, that is a very useful part.
ron
+3  A: 

It does the trick but I've got this notion that there's probably a one-liner for it ;)

The one-liner is probably not the pythonic way to do it :)

The method you have used looks fine.

Edit:

If you want to be cute:

return next( (i for i,(k,v) in enumerate(items) if k=='Spock'),None)

next takes a generator expression and returns the next value or the second argument (in this case None) once the generator has been exhausted.

HS
A: 

If you're often searching the same tuple, you can build a dict.

lookup_table = dict((key, i) for i, (key, unused) in enumerate(derp))

print lookup_table['Spock']
--> 2
Paul Hankin