patternpythonModerate
Creating zip but for dictionaries
Viewed 0 times
creatingbutzipfordictionaries
Problem
I found myself needed zip but for dictionaries, and wanted to know if there is any way I can make this shorter and more concise, and/or faster. Also I cannot figure out what the type hinting might be for the return (I would like to put it in the reStructuredText).
Output:
def dict_zip(*args):
"""The zip utility but for dictionaries
:param args:
A bunch of **identical** dicts
:type args:
dict
:return:
A dict of all the keys in the input dict,
mapped to a list of all the values fro that key
:rtype:
dict
"""
out = {i: [] for i in args[0]}
for dic in args:
for key in out:
out[key].append(dic[key])
return out
if __name__ == "__main__":
dict1 = {"first": True, "name": "John"}
dict2 = {"first": False, "name": "sue"}
print dict_zip(dict1, dict2)Output:
{'name': ['John', 'sue'], 'first': [True, False]}
Solution
A shorter version, functionally equivalent to yours:
That's assuming all dicts have the same keys, or more exactly, all dicts have at least all the keys present in the first dict.
To make it more robust and handle cases when dicts don't have the same keys:
Regarding type hints: not sure, but it might be something based on typing.MutableMapping. But that's Python 3.
EDIT
To add padding for keys which are not present in all dicts:
If you have to use Python 2 (if you can, upgrade to Py3 for your own good):
Notice that you could just do
def dict_zip(*dicts):
return {k: [d[k] for d in dicts] for k in args[0].keys()}That's assuming all dicts have the same keys, or more exactly, all dicts have at least all the keys present in the first dict.
To make it more robust and handle cases when dicts don't have the same keys:
def dict_zip(*dicts):
all_keys = {k for d in dicts for k in d.keys()}
return {k: [d[k] for d in dicts if k in d] for k in all_keys}Regarding type hints: not sure, but it might be something based on typing.MutableMapping. But that's Python 3.
EDIT
To add padding for keys which are not present in all dicts:
def dict_zip(*dicts, fillvalue=None):
all_keys = {k for d in dicts for k in d.keys()}
return {k: [d.get(k, fillvalue) for d in dicts] for k in all_keys}If you have to use Python 2 (if you can, upgrade to Py3 for your own good):
def dict_zip(*dicts, **kwargs):
fillvalue = kwargs.get('fillvalue', None)
all_keys = {k for d in dicts for k in d.keys()}
return {k: [d.get(k, fillvalue) for d in dicts] for k in all_keys}Notice that you could just do
kwargs.get('fillvalue') and if 'fillvalue' is not in kwargs, get would return None anyways. But explicit is better than implicit.Code Snippets
def dict_zip(*dicts):
return {k: [d[k] for d in dicts] for k in args[0].keys()}def dict_zip(*dicts):
all_keys = {k for d in dicts for k in d.keys()}
return {k: [d[k] for d in dicts if k in d] for k in all_keys}def dict_zip(*dicts, fillvalue=None):
all_keys = {k for d in dicts for k in d.keys()}
return {k: [d.get(k, fillvalue) for d in dicts] for k in all_keys}def dict_zip(*dicts, **kwargs):
fillvalue = kwargs.get('fillvalue', None)
all_keys = {k for d in dicts for k in d.keys()}
return {k: [d.get(k, fillvalue) for d in dicts] for k in all_keys}Context
StackExchange Code Review Q#160582, answer score: 14
Revisions (0)
No revisions yet.