无需重建的字典重用
补充说明:在提取Python字典中键值对子集的最佳方法中提到的方法是重新创建一个新的子键字典。这种方法比较慢(我试过)。下面shx2提到的使用Subdicview的方法在效率上非常不错。
我有一个Python字典,比如说:
d={"a1":Obj1, "a2":Obj2,"a3":Obj3,...,"a10":Obj10}
其中Obj1
到Objn
是我自己创建的Python类的一些对象。
问题是,在一个循环中要执行一亿次,每次迭代我需要不同的键子集,比如说我需要"a1"
到"a3"
,现在我做的是每次使用时都重新构建字典:
d1={"a1":Obj1, "a2":Obj2,"a3":Obj3}
这样我最终会进行一亿次字典的重建。
有没有更高效的方法来处理这种情况(例如,忽略我不感兴趣的d
中的键),而不需要在每次循环中都重建字典呢?
4 个回答
需要特别注意的是,set(dict)
在 Python 2.7 中并不是创建一个视图(就像被接受的答案所暗示的那样)。它实际上是创建了一个集合,而这样做的速度其实挺慢的。在 Python 2.7 中,字典的视图是通过字典上的 view*
方法来访问的(在这个例子中,我们想要使用 dict.viewkeys()
)。
你的问题不太清楚,不过如果我理解得没错的话,你可以使用 operator.itemgetter
。如果你的字典是这样的:
d = {'a1': 1, 'a2': 2, 'a3': 3, 'a4': 4, 'a5': 5}
那么:
>>> operator.itemgetter('a1', 'a3', 'a5')(d)
(1, 3, 5)
一个(注重速度的)解决方案是使用pandas.Series
。
import pandas as pd
series = pd.Series(d.values(), index = d.keys())
subseries1 = series[:3]
subseries2 = series[10:20]
...
如果你需要一些不连续的键的子集,你仍然可以使用类似的方式:
subseries3 = series.ix[[1,3,8]]
不过在这种情况下,可能会稍微慢一点,因为这种索引方式(和切片不同)会创建一个新的系列(而不是对原始系列的视图,这样会快很多)。
pandas.Series
的接口在某些方面和dict
很像,所以你不需要对其余的代码做太多(或者根本不需要)修改。
你可以使用下面这个“轻量级”的子字典视图类。这可能是最快的方法,因为它在每次循环时不需要创建新的字典(创建视图对象的速度很快)。
from UserDict import DictMixin
class SubDictView(DictMixin):
def __init__(self, dct, keys):
self._dct = dct
self._keys = keys
def __getitem__(self, key):
if key not in self._keys:
raise KeyError(key)
return self._dct[key]
def keys(self):
return set(self._dct) & self._keys
def __setitem__(self, key, val):
raise RuntimeError('SubDictView is read-only')
def __delitem__(self, key):
raise RuntimeError('SubDictView is read-only')
d = {'a': 1, 'b': 2, 'c': 3}
dv = SubDictView(d, {'b', 'c'})
print dv
# {'c': 3, 'b': 2}
print 'a' in dv
# False
print dv['b']
# 2
print dv.get('a', 999)
# 999
如果你已经把要用的键存储在一个set
里,那么在__init__
中就可以省去转换成set
的步骤,这样可以进一步提高速度。