我有一个字典d1
和一个列表l1
。
字典键是字符串,值是我自己定义的对象。如果它有帮助,我可以更详细地描述对象,但是现在,对象有一个列表属性names
,name
的某些元素可能会出现在l1
中,也可能不会出现在d1
中。
我想要做的是抛弃字典name
中的任何元素,其中所述元素中对象的l1
属性不包含{{1}中出现的任何元素。 1}}。
作为一个简单的例子:
l1 = ['cat', 'dog', 'mouse', 'horse', 'elephant',
'zebra', 'lion', 'snake', 'fly']
d1 = {'1':['dog', 'mouse', 'horse','orange', 'lemon'],
'2':['apple', 'pear','cat', 'mouse', 'horse'],
'3':['kiwi', 'lime','cat', 'dog', 'mouse'],
'4':['carrot','potato','cat', 'dog', 'horse'],
'5':['chair', 'table', 'knife']}
因此得到的字典或多或少相同,但每个列表的元素将是从1
到4
的键值对,不包括水果和蔬菜,并且不包含第5个键值par,因为l1
中没有任何家具值。
为此,我使用了嵌套列表/字典理解,如下所示:
d2 = {k: [a for a in l1 if a in d1[k]] for k in d1.keys()}
print(d2)
>>>>{'1': ['dog', 'mouse', 'horse'],
'3': ['cat', 'dog', 'mouse'],
'2': ['cat', 'mouse', 'horse'],
'5': [],
'4': ['cat', 'dog', 'horse']}
d2 = {k: v for k,v in d2.iteritems() if len(v)>0}
print(d2)
>>>>{'1': ['dog', 'mouse', 'horse'],
'3': ['cat', 'dog', 'mouse'],
'2': ['cat', 'mouse', 'horse'],
'4': ['cat', 'dog', 'horse'],}
这似乎有效,但对于大型词典,7000多个项目,需要大约20秒才能完成。本身并不可怕,但我需要在一个循环中执行此操作,该循环将迭代10,000次,因此目前它不可行。关于如何快速做到这一点的任何建议?
答案 0 :(得分:14)
您正在有效地计算字典值中出现的每个列表与列表l1
的集合交集。由于涉及线性搜索,因此使用用于集合交叉的列表是相当低效的。您应该将l1
转换为集合,然后使用set.intersection()
或设置成员资格测试(取决于结果是否可以接受)。
完整代码可能如下所示:
l1 = set(l1)
d2 = {k: [s for s in v if s in l1] for k, v in d1.iteritems()}
d2 = {k: v for k, v in d2.iteritems() if v}
在这里使用单个for
循环可能更好,而不是两个字典理解:
l1 = set(l1)
d2 = {}
for k, v in d1.iteritems():
v = [s for s in v if s in l1]
if v:
d2[k] = v
答案 1 :(得分:4)
问题不是字典理解,而是嵌套列表理解。您每次都在迭代相同的键。使用集合可以做得更好。
s1 = set(l1)
d2 = {k: list(s1.intersection(v)) for k, v in d1.items()}
答案 2 :(得分:1)
l1 = ['cat', 'dog', 'mouse', 'horse', 'elephant',
'zebra', 'lion', 'snake', 'fly']
d1 = {'1':['dog', 'mouse', 'horse','orange', 'lemon'],
'2':['apple', 'pear','cat', 'mouse', 'horse'],
'3':['kiwi', 'lime','cat', 'dog', 'mouse'],
'4':['carrot','potato','cat', 'dog', 'horse'],
'5':['chair', 'table', 'knife']}
def gen_items(valid_name_set, d):
for k, v in d.iteritems():
intersection = valid_name_set.intersection(v)
if intersection: # not empty
yield (k, intersection)
print dict(gen_items(set(l1), d1))
输出:
{'1': set(['dog', 'horse', 'mouse']),
'2': set(['cat', 'horse', 'mouse']),
'3': set(['cat', 'dog', 'mouse']),
'4': set(['cat', 'dog', 'horse'])}
可替换地:
from itertools import ifilter
from operator import itemgetter
set_l1 = set(l1)
d2 = dict(ifilter(itemgetter(1),
((k, set_l1.intersection(v)) for k, v in d1.iteritems())))
答案 3 :(得分:0)
使用set
:
>>> l1 = ['cat', 'dog', 'mouse', 'horse', 'elephant',
'zebra', 'lion', 'snake', 'fly']
>>> d1 = {'1':['dog', 'mouse', 'horse','orange', 'lemon'],
'2':['apple', 'pear','cat', 'mouse', 'horse'],
'3':['kiwi', 'lime','cat', 'dog', 'mouse'],
'4':['carrot','potato','cat', 'dog', 'horse'],
'5':['chair', 'table', 'knife']}
>>> l1_set = set(l1)
>>> d2 = dict((k, set(d1[k]) & l1_set) for k in d1.keys())
>>> d2
{'1': set(['horse', 'mouse', 'dog']), '3': set(['mouse', 'dog', 'cat']), '2': set(['horse', 'mouse', 'cat']), '5': set([]), '4': set(['horse', 'dog', 'cat'])}
>>> d2 = dict((k, v) for k,v in d2.iteritems() if v)
>>> d2
{'1': set(['horse', 'mouse', 'dog']), '3': set(['mouse', 'dog', 'cat']), '2': set(['horse', 'mouse', 'cat']), '4': set(['horse', 'dog', 'cat'])}
答案 4 :(得分:0)
如果您将l1
转换为set
并略微修改字典理解,则可以将其工作速度提高约三倍:
l1 = set(['cat', 'dog', 'mouse', 'horse', 'elephant',
'zebra', 'lion', 'snake', 'fly'])
d1 = {'1':['dog', 'mouse', 'horse','orange', 'lemon'],
'2':['apple', 'pear','cat', 'mouse', 'horse'],
'3':['kiwi', 'lime','cat', 'dog', 'mouse'],
'4':['carrot','potato','cat', 'dog', 'horse'],
'5':['chair', 'table', 'knife']}
d2 = {k: [a for a in d1[k] if a in l1] for k in d1.keys()}
print(d2)
以下是您对性能进行基准测试的方法:
import timeit
t = timeit.Timer(
"d2 = {k: [a for a in l1 if a in d1[k]] for k in d1.keys()}",
"from __main__ import (d1, l1)",
)
print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)
t = timeit.Timer(
'd2 = {k: [a for a in d1[k] if a in l1] for k in d1.keys()}',
"from __main__ import (d1, l1)",
)
print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)
我假设您无法控制d1
,并且在过滤之前将d1
的所有值转换为集合的速度太慢。