我有一个大字典对象,其中有几对键值对(大约16个),但我只对其中的3个感兴趣。如何最好地(最短/高效/最优雅)对这样的字典进行子集操作?
我所知道的最好方法是:
bigdict = {'a':1,'b':2,....,'z':26}
subdict = {'l':bigdict['l'], 'm':bigdict['m'], 'n':bigdict['n']}
我确信有比这更优雅的方法。
我有一个大字典对象,其中有几对键值对(大约16个),但我只对其中的3个感兴趣。如何最好地(最短/高效/最优雅)对这样的字典进行子集操作?
我所知道的最好方法是:
bigdict = {'a':1,'b':2,....,'z':26}
subdict = {'l':bigdict['l'], 'm':bigdict['m'], 'n':bigdict['n']}
我确信有比这更优雅的方法。
你可以尝试:
dict((k, bigdict[k]) for k in ('l', 'm', 'n'))
...或在Python版本2.7或更高版本中 Python 3 (感谢Fábio Diniz指出它也适用于2.7):
{k: bigdict[k] for k in ('l', 'm', 'n')}
更新:正如Håvard S指出的那样,我假设您知道字典中的键将存在于其中。如果您无法做出这种假设,请参阅他的答案。或者,如timbo在评论中指出的那样,如果您希望在bigdict
中缺少的键映射到None
,则可以执行以下操作:
{k: bigdict.get(k, None) for k in ('l', 'm', 'n')}
如果您使用的是Python 3,并且您希望新字典中仅包含原始字典中实际存在的键,您可以利用事实来查看对象实现了某些集合操作:
{k: bigdict[k] for k in bigdict.keys() & {'l', 'm', 'n'}}
稍微简短一些,至少:
wanted_keys = ['l', 'm', 'n'] # The keys you want
dict((k, bigdict[k]) for k in wanted_keys if k in bigdict)
dict((k,bigdict.get(k,defaultVal) for k in wanted_keys)
的方式。或者: - Thomas Andrews所有方法的速度比较:
更新于2020.07.13(感谢@user3780389):仅适用于bigdict中的键。
IPython 5.5.0 -- An enhanced Interactive Python.
Python 2.7.18 (default, Aug 8 2019, 00:00:00)
[GCC 7.3.1 20180303 (Red Hat 7.3.1-5)] on linux2
import numpy.random as nprnd
...: keys = nprnd.randint(100000, size=10000)
...: bigdict = dict([(_, nprnd.rand()) for _ in range(100000)])
...:
...: %timeit {key:bigdict[key] for key in keys}
...: %timeit dict((key, bigdict[key]) for key in keys)
...: %timeit dict(map(lambda k: (k, bigdict[k]), keys))
...: %timeit {key:bigdict[key] for key in set(keys) & set(bigdict.keys())}
...: %timeit dict(filter(lambda i:i[0] in keys, bigdict.items()))
...: %timeit {key:value for key, value in bigdict.items() if key in keys}
100 loops, best of 3: 2.36 ms per loop
100 loops, best of 3: 2.87 ms per loop
100 loops, best of 3: 3.65 ms per loop
100 loops, best of 3: 7.14 ms per loop
1 loop, best of 3: 577 ms per loop
1 loop, best of 3: 563 ms per loop
正如预期的那样:字典推导是最佳选项。
key
在bigdict
中不存在,将导致错误。 - naught101{key:bigdict[key] for key in bigdict.keys() & keys}
这个被接受的解决方法中,它实现了过滤功能,并且在我的机器上实际上比你列出的第一种方法更快,因为第一种方法没有进行过滤。事实上,对于这些非常大的键集,{key:bigdict[key] for key in set(keys) & set(bigdict.keys())}
似乎更快一些... - teichertinteresting_keys = ('l', 'm', 'n')
subdict = {x: bigdict[x] for x in interesting_keys if x in bigdict}
这个答案使用类似于所选答案的字典推导式,但不会在缺少项目时引发异常。
Python 2 版本:
{k:v for k, v in bigDict.iteritems() if k in ('l', 'm', 'n')}
Python 3 版本:
{k:v for k, v in bigDict.items() if k in ('l', 'm', 'n')}
{k: bigdict[k] for k in bigdict.keys() if k not in ['l', 'm', 'n']}
{k: v for k, v in bigdict.items() if k not in {'l', 'm', 'n'}}
- pierresegonnesubdict=dict([(x,bigdict[x]) for x in ['l', 'm', 'n']])
Python 3甚至支持以下内容:
subdict={a:bigdict[a] for a in ['l','m','n']}
请注意,您可以按照以下方式在字典中检查是否存在:
subdict=dict([(x,bigdict[x]) for x in ['l', 'm', 'n'] if x in bigdict])
针对 Python 3 的回复:
subdict={a:bigdict[a] for a in ['l','m','n'] if a in bigdict}
a
不在bigdict
中,则失败。 - Håvard S您也可以使用map
函数(这是一个非常有用的函数,值得学习):
sd = dict(map(lambda k: (k, l.get(k, None)), l))
示例:
large_dictionary = {'a1':123, 'a2':45, 'a3':344}
list_of_keys = ['a1', 'a3']
small_dictionary = dict(map(lambda key: (key, large_dictionary.get(key, None)), list_of_keys))
附注:我从之前的回答中借用了.get(key, None)
好的,这是我几次烦恼的事情,所以谢谢Jayesh提出了这个问题。
以上的答案似乎都是一个很好的解决方案,但如果您在代码中多处使用此功能,则封装该功能是有意义的。此外,这里有两种可能的用例:一种是您关心所有关键字是否在原始字典中,另一种则不在意。最好平等地对待这两种情况。
因此,我建议编写字典的子类,例如:
class my_dict(dict):
def subdict(self, keywords, fragile=False):
d = {}
for k in keywords:
try:
d[k] = self[k]
except KeyError:
if fragile:
raise
return d
Now you can pull out a sub-dictionary with
orig_dict.subdict(keywords)
用法示例:
#
## our keywords are letters of the alphabet
keywords = 'abcdefghijklmnopqrstuvwxyz'
#
## our dictionary maps letters to their index
d = my_dict([(k,i) for i,k in enumerate(keywords)])
print('Original dictionary:\n%r\n\n' % (d,))
#
## constructing a sub-dictionary with good keywords
oddkeywords = keywords[::2]
subd = d.subdict(oddkeywords)
print('Dictionary from odd numbered keys:\n%r\n\n' % (subd,))
#
## constructing a sub-dictionary with mixture of good and bad keywords
somebadkeywords = keywords[1::2] + 'A'
try:
subd2 = d.subdict(somebadkeywords)
print("We shouldn't see this message")
except KeyError:
print("subd2 construction fails:")
print("\toriginal dictionary doesn't contain some keys\n\n")
#
## Trying again with fragile set to false
try:
subd3 = d.subdict(somebadkeywords, fragile=False)
print('Dictionary constructed using some bad keys:\n%r\n\n' % (subd3,))
except KeyError:
print("We shouldn't see this message")
subdict(orig_dict, keys, ...)
? - musiphilmy_dict
。 - martineau这是另一种方法(我更喜欢Mark Longair的回答)
di = {'a':1,'b':2,'c':3}
req = ['a','c','w']
dict([i for i in di.iteritems() if i[0] in di and i[0] in req])
bigdict
不包含k
,则会失败。 - Håvard S{k: bigdict.get(k,None) for k in ('l', 'm', 'n')}
这段代码将会处理源字典中缺失指定键的情况,通过在新字典中将该键设为None来解决。 - timbobigdict.keys() & {'l', 'm', 'n'}
在 Python2.7 中应该改为bigdict.viewkeys() & {'l', 'm', 'n'}
。 - kxrdict
太大怎么办? - Adamantish