有没有办法在不使用Python中的for循环的情况下在元组中查找项?

时间:2011-12-06 23:22:33

标签: python loops tuples

我有Control个值的元组,我想找到一个名称匹配的元组。现在我用这个:

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

我可以比这简单吗?也许是这样的事情:

listView = controls.FirstOrDefault(c => c.name == "ListView")

3 个答案:

答案 0 :(得分:6)

这是一个选项:

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

请注意,如果不存在匹配项,则会引发StopIteration,因此您需要将其设置为try / except,如果获得StopIteration,则将其替换为默认值。

或者,您可以将默认值添加到iterable中,以便next调用始终成功。

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

如果您使用的是Python 2.5或更低版本,请将呼叫从next(iterable)更改为iterable.next()

答案 1 :(得分:2)

出于纯粹的好奇心,我将自己的答案与原始代码和F.J.的解决方案相结合,进行了比较性能测试。

您的解决方案似乎是最快的解决方案。我的解决方案检查控件元组的所有可能元素,因此随着元组大小的增加它会变慢。

以下是代码:

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)    

这是我系统上的输出:

[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! :)

答案 2 :(得分:1)

listView = filter(lambda c: c.name=="ListView", controls)[0]

如果不存在此类控件,则抛出 IndexError

有点深奥,但不需要尝试/除了:

listView = (lambda x: x[0] if x else None)(filter(lambda c: c.name=="ListView", controls))