One of my favourite methods in ruby is Hash.slice. It returns a new hash containing only the specified keys from the original hash - very handy!
It works like this:
h = {a: 1, b: 2, c: 3, d: 4}
h.slice(:a, :b)
# => {a: 1, b: 2}
TL;DR, this is my python equivalent:
import operator as op
def slice_dict(d: dict, keys: list) -> dict:
return dict(zip(keys, op.itemgetter(*keys)(d)))
slice
in PythonWe can definitely use a dictionary comprehension to achieve the same result:
def slice_dict(d: dict, keys: list) -> dict:
return {k: d[k] for k in keys if k in d}
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
slice_dict(d, ('a', 'b'))
# {'a': 1, 'b': 2}
We can use the dict
constructor to create a new dictionary from a list of tuples, which is a more efficient way to slice a dictionary:
def slice_dict(d: dict, keys: list) -> dict:
return dict((k, d[k]) for k in keys if k in d)
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
slice_dict(d, ('a', 'b'))
# {'a': 1, 'b': 2}
operator.itemgetter
We can use the [operator.itemgetter](https://docs.python.org/3/library/operator.html#operator.itemgetter)
function to create a callable that retrieves the specified keys from the dictionary.
First, a demonstration of how itemgetter
works:
import operator as op
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
getter = op.itemgetter('a', 'b')
# now we can use the getter to retrieve the values from a dictionary
getter(d)
# (1, 2)
We can then create a new dictionary by zipping the returned values with the keys:
keys = getter(d)
# (1, 2)
dict(zip(('a', 'b'), keys))
# {'a': 1, 'b': 2}
Combining these two steps, we can create a function that slices a dictionary:
import operator as op
def slice_dict(d: dict, keys: list) -> dict:
return dict(zip(keys, op.itemgetter(*keys)(d)))
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
slice_dict(d, ('a', 'b'))
# {'a': 1, 'b': 2}
Here are some quick benchmarks to compare the three methods:
I ran this in ipython so that I can use the %timeit
magic function
import operator as op
def slice_dict_comp(d: dict, keys: list) -> dict:
return {k: d[k] for k in keys if k in d}
def slice_dict_gen(d: dict, keys: list) -> dict:
return dict((k, d[k]) for k in keys if k in d)
def slice_dict_op(d: dict, keys: list) -> dict:
return dict(zip(keys, op.itemgetter(*keys)(d)))
for fn in [slice_dict_comp, slice_dict_gen, slice_dict_op]:
print(fn.__name__, fn(d, keys))
%timeit fn(d, keys)
function | time |
---|---|
slice_dict_comp | 746 ns |
slice_dict_gen | 1.33 μs |
slice_dict_op | 696 ns |