Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to find an item in a tuple without using a for loop in Python?

I have a tuple of Control values and I want to find the one with a matching name. Right now I use this:

listView
for control in controls:
    if control.name == "ListView":
        listView = control

Can I do it simpler than this? Perhaps something like:

listView = controls.FirstOrDefault(c => c.name == "ListView")
like image 418
Joan Venge Avatar asked Dec 06 '11 23:12

Joan Venge


People also ask

How do you search for items in a tuple?

Find the index of an element in tuple using index() Tuple provides a member function index() i.e. It returns the index for first occurrence of x in the tuple. Also, if element is not found in tuple then it will throw an exception ValueError.

Can we access elements of tuple through iteration?

Tuples are immutable, and usually contain a heterogeneous sequence of elements that are accessed via unpacking or indexing (or even by attribute in the case of namedtuples ). Lists are mutable, and their elements are usually homogeneous and are accessed by iterating over the list.


2 Answers

Here is one option:

listView = next(c for c in controls if c.name == "ListView")

Note that this will raise a StopIteration if no matching item exists, so you will need to put this in a try/except and replace it with a default if you get a StopIteration.

Alternatively you can add your default value to the iterable so the next call always succeeds.

from itertools import chain
listView = next(chain((c for c in controls if c.name == "ListView"), [default])

If you are using Python 2.5 or lower change the call from next(iterable) to iterable.next().

like image 195
Andrew Clark Avatar answered Oct 09 '22 17:10

Andrew Clark


Out of sheer curiosity, I integrated my own answer with your original code and F.J.'s solutions to make a comparative performance test.

It seems that your solution is the fastest of them all. My solution check all possible elements of the controls tuple, so it will be slower as the size of the tuple increases.

Here is the code:

from timeit import Timer as T
from itertools import chain, dropwhile

class control(object):
    def __init__(self, name):
        self.name = name

def johan_venge(tuple_):
    for el in tuple_:
        if el.name == 'foobar':
            return el
    return None

def mac(tuple_):
    return filter(lambda x : x.name == 'foobar', tuple_)[0]

def mac2(tuple_):
    return list(dropwhile(lambda x : x.name != 'foobar', tuple_))[0]

def fj(tuple_):
    return next(c for c in tuple_ if c.name == 'foobar')

def fj2(tuple_):
    return next(chain((c for c in tuple_ if c.name == 'foobar')))

if __name__ == '__main__':
    REPS = 10000
    controls = (control('hello'), control('world'), control('foobar'))
    print T(lambda : johan_venge(controls)).repeat(number = REPS)
    print T(lambda : mac(controls)).repeat(number = REPS)
    print T(lambda : mac2(controls)).repeat(number = REPS)
    print T(lambda : fj(controls)).repeat(number = REPS)
    print T(lambda : fj2(controls)).repeat(number = REPS)    

and here is the output on my system:

[0.005961179733276367, 0.005975961685180664, 0.005918025970458984]
[0.013427019119262695, 0.013586044311523438, 0.013450145721435547]
[0.024325847625732422, 0.0254058837890625, 0.02396702766418457]
[0.014491081237792969, 0.01442408561706543, 0.01484990119934082]
[0.01691603660583496, 0.016616106033325195, 0.016437053680419922]

HTH! :)

like image 20
mac Avatar answered Oct 09 '22 19:10

mac