问题
I have a big dictionary object that has several key value pairs (about 16), but I am only interested in 3 of them. What is the best way (shortest/efficient/most elegant) to achieve that?
The best I know is:
bigdict = {\'a\':1,\'b\':2,....,\'z\':26}
subdict = {\'l\':bigdict[\'l\'], \'m\':bigdict[\'m\'], \'n\':bigdict[\'n\']}
I am sure there is a more elegant way than this. Ideas?
回答1:
You could try:
dict((k, bigdict[k]) for k in ('l', 'm', 'n'))
... or in Python 3 Python versions 2.7 or later (thanks to Fábio Diniz for pointing that out that it works in 2.7 too):
{k: bigdict[k] for k in ('l', 'm', 'n')}
Update: As Håvard S points out, I'm assuming that you know the keys are going to be in the dictionary - see his answer if you aren't able to make that assumption. Alternatively, as timbo points out in the comments, if you want a key that's missing in bigdict to map to None, you can do:
{k: bigdict.get(k, None) for k in ('l', 'm', 'n')}
If you're using Python 3, and you only want keys in the new dict that actually exist in the original one, you can use the fact to view objects implement some set operations:
{k: bigdict[k] for k in bigdict.keys() & {'l', 'm', 'n'}}
回答2:
A bit shorter, at least:
wanted_keys = ['l', 'm', 'n'] # The keys you want
dict((k, bigdict[k]) for k in wanted_keys if k in bigdict)
回答3:
interesting_keys = ('l', 'm', 'n')
subdict = {x: bigdict[x] for x in interesting_keys if x in bigdict}
回答4:
A bit of speed comparison for all mentioned methods:
Python 2.7.11 |Anaconda 2.4.1 (64-bit)| (default, Jan 29 2016, 14:26:21) [MSC v.1500 64 bit (AMD64)] on win32
In[2]: import numpy.random as nprnd
keys = nprnd.randint(1000, size=10000)
bigdict = dict([(_, nprnd.rand()) for _ in range(1000)])
%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 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: 3.09 ms per loop
100 loops, best of 3: 3.72 ms per loop
100 loops, best of 3: 6.63 ms per loop
10 loops, best of 3: 20.3 ms per loop
100 loops, best of 3: 20.6 ms per loop
As it was expected: dictionary comprehensions are the best option.
回答5:
This answer uses a dictionary comprehension similar to the selected answer, but will not except on a missing item.
python 2 version:
{k:v for k, v in bigDict.iteritems() if k in ('l', 'm', 'n')}
python 3 version:
{k:v for k, v in bigDict.items() if k in ('l', 'm', 'n')}
回答6:
Maybe:
subdict=dict([(x,bigdict[x]) for x in ['l', 'm', 'n']])
Python 3 even supports the following:
subdict={a:bigdict[a] for a in ['l','m','n']}
Note that you can check for existence in dictionary as follows:
subdict=dict([(x,bigdict[x]) for x in ['l', 'm', 'n'] if x in bigdict])
resp. for python 3
subdict={a:bigdict[a] for a in ['l','m','n'] if a in bigdict}
回答7:
You can also use map (which is a very useful function to get to know anyway):
sd = dict(map(lambda k: (k, l.get(k, None)), l))
Example:
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))
PS. I borrowed the .get(key, None) from a previous answer :)
回答8:
Okay, this is something that has bothered me a few times, so thank you Jayesh for asking it.
The answers above seem like as good a solution as any, but if you are using this all over your code, it makes sense to wrap the functionality IMHO. Also, there are two possible use cases here: one where you care about whether all keywords are in the original dictionary. and one where you don't. It would be nice to treat both equally.
So, for my two-penneth worth, I suggest writing a sub-class of dictionary, e.g.
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)
Usage examples:
#
## 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")
If you run all the above code, you should see (something like) the following output (sorry for the formatting):
Original dictionary:
{'a': 0, 'c': 2, 'b': 1, 'e': 4, 'd': 3, 'g': 6, 'f': 5, 'i': 8, 'h': 7, 'k': 10, 'j': 9, 'm': 12, 'l': 11, 'o': 14, 'n': 13, 'q': 16, 'p': 15, 's': 18, 'r': 17, 'u': 20, 't': 19, 'w': 22, 'v': 21, 'y': 24, 'x': 23, 'z': 25}Dictionary from odd numbered keys:
{'a': 0, 'c': 2, 'e': 4, 'g': 6, 'i': 8, 'k': 10, 'm': 12, 'o': 14, 'q': 16, 's': 18, 'u': 20, 'w': 22, 'y': 24}subd2 construction fails:
original dictionary doesn't contain some keysDictionary constructed using some bad keys:
{'b': 1, 'd': 3, 'f': 5, 'h': 7, 'j': 9, 'l': 11, 'n': 13, 'p': 15, 'r': 17, 't': 19, 'v': 21, 'x': 23, 'z': 25}
回答9:
Yet another one (I prefer Mark Longair's answer)
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])
来源:https://stackoverflow.com/questions/5352546/extract-subset-of-key-value-pairs-from-python-dictionary-object