Python - пересечение между списком и ключами словаря
У меня есть список, который выглядит так:
l1 = ['200:200', '90:728']
У меня есть словарь, который выглядит так:
d1 = {'200:200':{'foo':'bar'},'300:300':{'foo':'bar'}}
Мне нужно отфильтровать дикториал, где только ключи находятся в l1. Диктофон должен выглядеть так:
result = {'200:200':{'foo':'bar'}}
В сущности, пересечение списка и ключей dict при возврате подраздела dict.
Как мне сделать это эффективно, когда время является проблемой для больших наборов?
Спасибо
Ответы
Ответ 1
Вы можете использовать следующий код:
keys = set(l1).intersection(set(d1.keys()))
result = {k:d1[k] for k in keys}
EDIT:. Как говорят комментаторы, вы можете заменить первую строку на Python 2.x:
keys = set(l1).intersection(d1)
И в Python 3.x:
keys = d1.keys() & l1
Ответ 2
В 3.x это может быть просто:
>>> {k: d1[k] for k in (d1.keys() & l1)}
{'200:200': {'foo': 'bar'}}
В разделе 2.7 вы можете использовать dict.viewkeys()
для воссоздания этой функции:
>>> {k: d1[k] for k in (d1.viewkeys() & l1)}
{'200:200': {'foo': 'bar'}}
В более старых версиях 2.x это несколько более подробный:
>>> {k: d1[k] for k in (set(d1).intersection(l1))}
{'200:200': {'foo': 'bar'}}
Ответ 3
Не уверен в производительности каждого решения, но я бы сделал:
{k: v for k, v in d1.items() if k in l1}
Ответ 4
Вы можете использовать понимание списка в конструкторе dict:
result = dict([(k,d1[k]) for k in l1 if k in d1])
Если вы беспокоитесь об удалении повторяющихся ключей, сначала сделайте l1 в наборе:
result = dict([(k,d1[k]) for k in set(l1) if k in d1])
Ответ 5
Определите эффективность. В любом случае, что бы я сделал. Если бы это было слишком медленно, я бы, вероятно, переместил его в Cython.
s1 = set(l1)
s2 = set(d1.keys())
s3 = s1 & s2
# now you can access d1 using only keys in s3, or construct a new dict if you like
d2 = dict([(k,d1[k]) for k in s3])
Ответ 6
Если распределение памяти и освобождение делают этот процесс слишком длинным, itertools на помощь.
import itertools
result = {dict_key:d1[dict_key] for dict_key in itertools.ifilter(lambda list_item: list_item in d1, l1) }
Это лишний раз выделяет память для всей новой коллекции, а l1 легко может быть итератором вместо списка.