Skip to content
Advertisement

Slicing a dictionary

I have a dictionary, and would like to pass a part of it to a function, that part being given by a list (or tuple) of keys. Like so:

# the dictionary
d = {1:2, 3:4, 5:6, 7:8}

# the subset of keys I'm interested in
l = (1,5)

Now, ideally I’d like to be able to do this:

>>> d[l]
{1:2, 5:6}

… but that’s not working, since it will look for a key matching the tuple (1,5), the same as d[1,5].

d{1,5} isn’t even valid Python (as far as I can tell …), though it might be handy: The curly braces suggest an unordered set or a dictionary, so returning a dictionary containing the specified keys would look very plausible to me.

d[{1,5}] would also make sense (“here’s a set of keys, give me the matching items”), and {1, 5} is an unhashable set, so there can’t be a key that matches it — but of course it throws an error, too.

I know I can do this:

>>> dict([(key, value) for key,value in d.iteritems() if key in l])
{1: 2, 5: 6}

or this:

>>> dict([(key, d[key]) for key in l])

which is more compact … but I feel there must be a “better” way of doing this. Am I missing a more elegant solution?

(I’m using Python 2.7)

Advertisement

Answer

You should be iterating over the tuple and checking if the key is in the dict not the other way around, if you don’t check if the key exists and it is not in the dict you are going to get a key error:

print({k:d[k] for k in l if k in d})

Some timings:

 {k:d[k] for k in set(d).intersection(l)}

In [22]: %%timeit                        
l = xrange(100000)
{k:d[k] for k in l}
   ....: 
100 loops, best of 3: 11.5 ms per loop

In [23]: %%timeit                        
l = xrange(100000)
{k:d[k] for k in set(d).intersection(l)}
   ....: 
10 loops, best of 3: 20.4 ms per loop

In [24]: %%timeit                        
l = xrange(100000)
l = set(l)                              
{key: d[key] for key in d.viewkeys() & l}
   ....: 
10 loops, best of 3: 24.7 ms per

In [25]: %%timeit                        

l = xrange(100000)
{k:d[k] for k in l if k in d}
   ....: 
100 loops, best of 3: 17.9 ms per loop

I don’t see how {k:d[k] for k in l} is not readable or elegant and if all elements are in d then it is pretty efficient.

Advertisement