I would propose to you that your own method is the best way to find the first item in a list matching a criteria.
It is straightforward and will break out of the loop once the desired target is found.
It is also the fastest. Here compared to numerous way to return the FIRST dict in the list with '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)
If the value 'id'==20 is found, prints:
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}
And, if not found, prints:
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
Of course, as written, these functions only return the first dict in this list with 'id'==20. If you want ALL of them, you might use a list comprehension or filter with a lambda.
You can see that as you wrote the function originally, modified to return a list instead, it is still competitive:
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) )
Using the same code to time it, these functions print:
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}]
In this case, the list comprehension is better.
next(filter(...))item. Was that intended?