Пробовал различные методы следующим образом.
def _next(lst, name):
" Search through list for ditionary, and update selected "
d = next((d for d in lst if d["name"] == name), None)
if d:
d['selected'] = True
def _filter(lst, name):
" Filter list based upon name field of dictionary"
filtered = filter(lambda d: d['name'] == name, lst)
d = next(filtered, None)
if d:
d['selected'] = True
def _map(lst, name):
" Map each dictionary to its name field, then find index "
mapped = list(map(lambda d: d['name'], lst))
try:
i = mapped.index(name)
d = lst[i]
d['selected'] = True
except err:
pass
def _for_loop(lst, name):
" Using for loop to find dictionary "
for d in lst:
if d['name'] == name:
d['selected'] = True
break
Результат
Используя список из 2 миллионов элементов, каждый словарь
_next ( Генератор) и for_l oop провели лучшие и сопоставимые времена. Они похожи, за исключением того, что _next использует генератор (поэтому более экономно, чем for-l oop).
- _next (Поиск в списке и обновление выбранного)
15,9 мс ± 456 мкс на л oop (среднее ± стандартное отклонение из 7 прогонов, 100 циклов в каждом)
фильтр-фильтр Список на основе поля имени словаря
35,9 мс ± 2,3 мс на л oop (среднее ± стандартное отклонение из 7 прогонов, по 10 циклов в каждом)
map - сопоставить каждый словарь с его полем имени, затем найти индекс
43,1 мс ± 3,22 мс на л oop (среднее ± стандартное отклонение из 7 прогонов, по 10 циклов в каждом) for_l oop
_for_l oop - Использует для l oop поиск словаря в списке
15,8 мс ± 500 мкс на л oop (среднее ± стандартное отклонение из 7 прогонов, 100 петель каждая)
Тестовый код
N = 2000000
names = ['next', 'filter', 'map', 'for_loop']
for i, func in enumerate([_next, _filter, _map, _for_loop]):
# Regenerates list since a field is set each time (probably unnecessary)
alist = [{'name': str(x), "selected": False} for x in range(N)]
print(names[i])
%timeit func(alist, str(N-1)) # find the last item in list
Тест в худшем случае (с идентичными ключами)
Протестируйте с 2 миллионами идентичных ключей.
В основном перепроверьте с 2 изменениями: (1) перепроверьте фильтр и функции for_l oop, поскольку их легче иметь с несколькими идентичными ключами (2) Удалите ранний разрыв, когда ключ найдено
Новые функции
def _filter(lst, name):
" Filter list based upon name field of dictionary"
filtered = filter(lambda d: d['name'] == name, lst)
for d in list(filtered):
d['selected'] = True
def _for_loop(lst, name):
" Using for loop to find dictionary "
for d in lst:
if d['name'] == name:
d['selected'] = True
Код теста
names = ['filter', 'for_loop']
for i, func in enumerate([_filter, _for_loop]):
alist = [{'name': str(1), "selected": False} for x in range(N)]
print(names[i])
%timeit func(alist, str(1)) # set found items in list
Результаты
Очень похоже результаты как предыдущий тест.
filter
36 ms ± 3.36 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
for_loop
15.8 ms ± 780 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)