2012-06-22 48 views
12

我有一个看起来像这样的列表:的Python - 字典列表和按键之间的交叉

l1 = ['200:200', '90:728'] 

我有一本字典,看起来像这样:

d1 = {'200:200':{'foo':'bar'},'300:300':{'foo':'bar'}} 

我需要得到过滤只有密钥在l1中的dictioary。该字典应该是这样的:

result = {'200:200':{'foo':'bar'}} 

本质列表的交集和字典的键而返回字典的小节。

如何有效地做到这一点,时间是一个大集合的问题?

感谢

回答

23

您可以使用下面的代码:

keys = set(l1).intersection(set(d1.keys())) 
result = {k:d1[k] for k in keys} 

编辑:作为评论者建议你可以替换的第一线,在Python 2.x的:

keys = set(l1).intersection(d1) 

而在Python 3.x中:

keys = d1.keys() & l1 
+0

请注意,在3.x中,字典视图是类似设置的,因此您不需要将其包装在'set()'中。事实上,在3.x中,整个顶行可以是'keys = d1.keys()&l1'。 –

+1

@Lattyware你不需要将它转换为2.x中的一个集合 – jamylak

+4

甚至不需要keys(),'set(l1).intersection(d1)' – georg

0

你可以在字典构造函数中使用列表理解:

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]) 
+0

密钥可能不在'd1'中。这不起作用。 –

+0

另请注意,您可以在我的解决方案中执行dict生成器表达式。所以'{k:v for k,v in arr}'。这甚至有处理重复的好处。 – JPvdMerwe

+0

@JPvdMerwe这是一个字典理解,而不是一个字典生成器表达式 - 生成器表达式是懒惰的,字典理解不是。 –

4

在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'}} 
+0

我检查了文档。看起来'viewkeys()'在2.7中可用,而不仅仅是2.7.3。它出现在我的Python 2.7.1副本中 – JPvdMerwe

+0

@JPvdMerwe很高兴知道,更新。 –

3

不知道有关每个解决方案的性能,但我会做到:

{k: v for k, v in d1.items() if k in l1} 
+2

即使当l1中的一个成员不是d1中的一个键时,这也可以工作,而其他许多人将会失败。 –

0

定义快捷。无论如何,这是我会做的。如果速度太慢,我可能会把它移到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]) 
0

如果内存分配和释放正在使这个过程花费太长时间,itertools就会解救。

import itertools 
result = {dict_key:d1[dict_key] for dict_key in itertools.ifilter(lambda list_item: list_item in d1, l1) } 

这不会为整个新集合不必要地分配内存,而l1可能很容易成为迭代器而不是列表。