Question

I have a data structure which is a collection of tuples like this:

things = ( (123, 1, "Floogle"), (154, 33, "Blurgle"), (156, 55, "Blarg") )

The first and third elements are each unique to the collection.

What I want to do is retrieve a specific tuple by referring to the third value, eg:

>>> my_thing = things.get( value(3) == "Blurgle" )
(154, 33, "Blurgle")

There must be a better way than writing a loop to check each value one by one!

Was it helpful?

Solution

If things is a list, and you know that the third element is uniqe, what about a list comprehension?

>> my_thing = [x for x in things if x[2]=="Blurgle"][0]

Although under the hood, I assume that goes through all the values and checks them individually. If you don't like that, what about changing the my_things structure so that it's a dict and using either the first or the third value as the key?

OTHER TIPS

A loop (or something 100% equivalent like a list comprehension or genexp) is really the only approach if your outer-level structure is a tuple, as you indicate -- tuples are, by deliberate design, an extremely light-weight container, with hardly any methods in fact (just the few special methods needed to implement indexing, looping and the like;-).

Lightning-fast retrieval is a characteristic of dictionaries, not tuples. Can't you have a dictionary (as the main structure, or as a side auxiliary one) mapping "value of third element" to the subtuple you seek (or its index in the main tuple, maybe)? That could be built with a single loop and then deliver as many fast searches as you care to have!

If you choose to loop, a genexp as per Brian's comment an my reply to it is both more readable and on average maybe twice as fast than a listcomp (as it only does half the looping):

my_thing = next(item for item in things if item[2] == "Blurgle")

which reads smoothly as "the next item in things whose [2] sub-item equale Blurgle" (as you're starting from the beginning the "next" item you find will be the "first" -- and, in your case, only -- suitable one).

If you need to cover the case in which no item meets the predicate, you can pass next a second argument (which it will return if needed), otherwise (with no second argument, as in my snippet) you'll get a StopIteration exception if no item meets the predicate -- either behavior may be what you desire (as you say the case should never arise, an exception looks suitable for your particular application, since the occurrence in question would be an unexpected error).

if you have to do this type of search multiple times, why don't you convert things to things_dict one time , then it will be easy and faster to search later on

things = ( (123, 1, "Floogle"), (154, 33, "Blurgle"), (156, 55, "Blarg") )

things_dict = {}
for t in things:
    things_dict[t[2]] = t

print things_dict['Blarg']
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top