Python:在列表中获取项目,其中dict键是使用lambda的某个值

时间:2014-06-29 15:52:18

标签: python lambda

是否可以使用lambda获取?我知道我们可以用lambda做sorted函数,它非常有用。

是否有一种简短的方式来获取列表中的对象,其中键'id'处的对象等于20

我们当然可以在整个事情上使用循环和循环。

x = [
    {'Car': 'Honda', 'id': 12},
    {'Car': 'Mazda', 'id': 45},
    {'Car': 'Toyota', 'id': 20}
    ]

desired_val = None
for item in list:
    if item['id'] == 20:
        desired_val = item
        break

是否可以使用lambda实现相同的功能?我对lambda知之甚少。

4 个答案:

答案 0 :(得分:5)

根据你的要求使用lambda,使用生成器表达式,通常认为它比filter更具可读性,并注意这在Python 2或3中同样有效。

lambda x: next(i for i in x if i['id'] == 20)

用法:

>>> foo = lambda x: next(i for i in x if i['id'] == 20)
>>> foo(x)
{'Car': 'Toyota', 'id': 20}

这种lambda的使用可能不是很有用。我们可以很容易地定义一个函数:

def foo(x):
    return next(i for i in x if i['id'] == 20)

但我们可以给它文档字符串,它知道它自己的名字,并且有其他有趣的属性,匿名函数(我们接着命名)没有。

此外,我真的认为你所得到的是表达式的过滤器部分。

filter(lambda x: x[id]==20, x)

我们已使用生成器表达式的条件部分替换了该功能。生成器表达式的功能部分(方括号中的列表推导)同样替换map

答案 1 :(得分:5)

此处不必使用lambda。 Lambda不是一个神奇的东西,它只是写一个简单函数的简写。它的较少比普通的函数编写方式更强大,而不是更多。 (这并不是说有时它不是非常方便,只是它没有超级大国。)

无论如何,您可以使用带默认参数的生成器表达式。请注意,我在这里返回对象本身,而不是20,因为这对我来说更有意义。

>>> somelist = [{"id": 10, "x": 1}, {"id": 20, "y": 2}, {"id": 30, "z": 3}]
>>> desired_val = next((item for item in somelist if item['id'] == 20), None)
>>> print(desired_val)
{'y': 2, 'id': 20}
>>> desired_val = next((item for item in somelist if item['id'] == 21), None)
>>> print(desired_val)
None

答案 2 :(得分:4)

在Py3k中filter返回一个迭代器,因此您可以使用next获取其第一个值:

val = next(filter(lambda x: x['id'] == 20, list))

对于Python 2,使用itertools.ifilter,因为内置的filter使用结果构建列表:

from itertools import ifilter
val = next(ifilter(lambda x: x['id'] == 20, list))

考虑将默认值传递给next,如果是空迭代器将返回该值:

In [3]: next(filter(bool, [False]), 'default value here')
Out[3]: 'default value here'

答案 3 :(得分:4)

我建议你自己的方法是找到符合条件的列表中第一个项目的最佳方法。

这很简单,一旦找到所需的目标,就会突破循环。

这也是最快的。这里比较了使用'id'==20返回列表中FIRST dict的多种方法:

from __future__ import print_function

def f1(LoD, idd=20):
    # loop until first one is found then break and return the dict found
    desired_dict = None
    for di in LoD:
        if di['id'] == idd:
            desired_dict = di
            break
    return desired_dict

def f2(LoD, idd=20):
    # The genexp goes through the entire list, then next() returns either the first or None
    return next((di for di in LoD if di['id'] == idd), None)   

def f3(LoD, idd=20):
    # NOTE: the 'filter' here is ifilter if Python2
    return next(filter(lambda di: di['id']==idd, LoD), None)

def f4(LoD, idd=20):
    desired_dict=None
    i=0
    while True:
        try:
            if LoD[i]['id']==idd:
                desired_dict=LoD[i]
                break
            else: 
                i+=1
        except IndexError:
            break

    return desired_dict         

def f5(LoD, idd=20):
    try:
        return [d for d in LoD if d['id']==idd][0]               
    except IndexError:
        return None            


if __name__ =='__main__':
    import timeit   
    import sys
    if sys.version_info.major==2:
        from itertools import ifilter as filter

    x = [
        {'Car': 'Honda', 'id': 12},
        {'Car': 'Mazda', 'id': 45},
        {'Car': 'Toyota', 'id': 20}
        ]  * 10   # the '* 10' makes a list of 30 dics...

    result=[]    
    for f in (f1, f2, f3, f4, f5):
        fn=f.__name__
        fs="f(x, idd=20)"
        ft=timeit.timeit(fs, setup="from __main__ import x, f", number=1000000)
        r=eval(fs)
        result.append((ft, fn, r, ))         

    result.sort(key=lambda t: t[0])           

    for i, t in enumerate(result):
        ft, fn, r = t
        if i==0:
            fr='{}: {:.4f} secs is fastest\n\tf(x)={}\n========'.format(fn, ft, r)   
        else:
            t1=result[0][0]
            dp=(ft-t1)/t1
            fr='{}: {:.4f} secs - {} is {:.2%} faster\n\tf(x)={}'.format(fn, ft, result[0][1], dp, r)

        print(fr)

如果找到值'id'==20,则打印:

f1: 0.4324 secs is fastest
    f(x)={'Car': 'Toyota', 'id': 20}
========
f4: 0.6963 secs - f1 is 61.03% faster
    f(x)={'Car': 'Toyota', 'id': 20}
f3: 0.9077 secs - f1 is 109.92% faster
    f(x)={'Car': 'Toyota', 'id': 20}
f2: 0.9840 secs - f1 is 127.56% faster
    f(x)={'Car': 'Toyota', 'id': 20}
f5: 2.6065 secs - f1 is 502.77% faster
    f(x)={'Car': 'Toyota', 'id': 20}

如果没有找到,请打印:

f1: 1.6084 secs is fastest
    f(x)=None
========
f2: 2.0128 secs - f1 is 25.14% faster
    f(x)=None
f5: 2.5494 secs - f1 is 58.50% faster
    f(x)=None
f3: 4.4643 secs - f1 is 177.56% faster
    f(x)=None
f4: 5.7889 secs - f1 is 259.91% faster
    f(x)=None

当然,正如所写,这些函数只返回此列表中第一个带有'id'== 20的dict。如果你想要所有这些,你可以使用列表理解或过滤器与lambda。

您可以看到,在您编写原始函数时,修改为返回列表,它仍具有竞争力:

def f1(LoD, idd):
    desired_lst = []
    for item in LoD:
        if item['id'] == idd:
            desired_lst.append(item)

    return desired_lst

def f2(LoD, idd):
    return [d for d in LoD if d['id']==idd]    

def f3(LoD, idd):
    return list(filter(lambda x: x['id']==idd, LoD) )   

使用相同的代码计时,这些函数打印:

f2: 2.3849 secs is fastest
    f(x)=[{'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}]
========
f1: 3.0051 secs - f2 is 26.00% faster
    f(x)=[{'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}]
f3: 5.2386 secs - f2 is 119.66% faster
    f(x)=[{'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}, {'Car': 'Toyota', 'id': 20}]

在这种情况下,列表理解更好。