Python:使用lambda获取列表中的项,其中dict key是某个值
是否可以使用lambda提取?我知道我们可以用lambda做Python:使用lambda获取列表中的项,其中dict key是某个值,python,lambda,Python,Lambda,是否可以使用lambda提取?我知道我们可以用lambda做排序函数,它非常有用 是否有一种在列表中获取对象的简单方法,其中键'id'处的对象等于,比如说20 我们当然可以在整个过程中使用循环 x = [ {'Car': 'Honda', 'id': 12}, {'Car': 'Mazda', 'id': 45}, {'Car': 'Toyota', 'id': 20} ] desired_val = None for item in list: if
排序
函数,它非常有用
是否有一种在列表中获取对象的简单方法,其中键'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
实现相同的功能?我对Py3k中的lambda
不是很了解,因为它返回一个迭代器,所以您可以使用来获取它的第一个值:
val = next(filter(lambda x: x['id'] == 20, list))
对于Python2使用,因为内置的过滤器
构造带有结果的列表:
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'
按照您的要求使用lambda和生成器表达式,这通常被认为比过滤器更可读,请注意,这在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)
但是我们可以给它docstrings,它知道自己的名字,还有其他一些匿名函数(我们当时称之为匿名函数)没有的有趣属性
另外,我真的认为你得到的是表达式的过滤部分
在
我们已将该功能替换为生成器表达式的条件部分。生成器表达式的功能部分(方括号中的列表理解)同样也在使用
lambda替换map
。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
我建议您,您自己的方法是在列表中找到符合条件的第一项的最佳方法
它很简单,一旦找到所需的目标,它就会跳出循环
它也是最快的。这里与返回列表中第一个dict且'id'==20
的多种方法相比:
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
如果未找到,则打印:
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
当然,如前所述,这些函数只返回此列表中第一个dict的'id'==20。如果您想要所有这些,您可以使用带有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}]
在这种情况下,列表理解更好 我只是想知道这是更快还是使用lambda更快。时间到了,可以用lambda搜索吗?这就是我需要的。我可以计时,这不是问题所在。在Python3中,您可以使用next(filter(…)
您说“获取对象”,但您将所需的值设置为20,而不是项。这是故意的吗?@DSM啊,对不起。在我的实现中,它是一个对象,但我任意将val设置为20。我理解这会如何伤害未来的用户。我会修复它。对于Python3来说,这是可以的,但是对于Python2,它将首先创建整个列表,然后使用第一个元素并丢弃其余的元素。也许更愿意使用itertools.ifilter
?@tobias_k在注意到您的建议之前我已经添加了它:)看起来像是简单的函数循环和中断构造击败了生成器。干得好。谢谢你,道格先生(好名字,很有趣)先生。这很有帮助。一只狗刚刚回答了一个编程问题:O