flatten-dict


Nameflatten-dict JSON
Version 0.4.2 PyPI version JSON
download
home_pagehttps://github.com/ianlini/flatten-dict
SummaryA flexible utility for flattening and unflattening dict-like objects in Python.
upload_time2021-08-08 09:56:51
maintainer
docs_urlNone
authorIan Lin
requires_python>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            flatten-dict
============
.. image:: https://github.com/ianlini/flatten-dict/actions/workflows/main.yml/badge.svg
   :target: https://github.com/ianlini/flatten-dict/actions
.. image:: https://img.shields.io/pypi/v/flatten-dict.svg
   :target: https://pypi.org/project/flatten-dict/
.. image:: https://img.shields.io/pypi/l/flatten-dict.svg
   :target: https://github.com/ianlini/flatten-dict/blob/master/LICENSE
.. image:: https://img.shields.io/github/stars/ianlini/flatten-dict.svg?style=social
   :target: https://github.com/ianlini/flatten-dict

A flexible utility for flattening and unflattening dict-like objects in Python.


Introduction
------------
This package provides a function ``flatten()`` for flattening dict-like objects in Python 2.7 and 3.5~3.8.
It also provides some key joining methods (reducer), and you can choose the reducer you want or even implement your own reducer.
You can also invert the resulting flat dict using ``unflatten()``.

Installation
------------

.. code-block:: bash

   pip install flatten-dict

Documentation
-------------

Flatten
```````

.. code-block:: python

   def flatten(d, reducer='tuple', inverse=False, enumerate_types=(), keep_empty_types=()):
       """Flatten `Mapping` object.

       Parameters
       ----------
       d : dict-like object
           The dict that will be flattened.
       reducer : {'tuple', 'path', 'underscore', 'dot', Callable}
           The key joining method. If a `Callable` is given, the `Callable` will be
           used to reduce.
           'tuple': The resulting key will be tuple of the original keys.
           'path': Use `os.path.join` to join keys.
           'underscore': Use underscores to join keys.
           'dot': Use dots to join keys.
       inverse : bool
           Whether you want invert the resulting key and value.
       max_flatten_depth : int
           Maximum depth to merge.
       enumerate_types : Sequence[type]
           Flatten these types using `enumerate`.
           For example, if we set `enumerate_types` to ``(list,)``,
           `list` indices become keys: ``{'a': ['b', 'c']}`` -> ``{('a', 0): 'b', ('a', 1): 'c'}``.
       keep_empty_types : Sequence[type]
           By default, ``flatten({1: 2, 3: {}})`` will give you ``{(1,): 2}``, that is, the key ``3``
           will disappear.
           This is also applied for the types in `enumerate_types`, that is,
           ``flatten({1: 2, 3: []}, enumerate_types=(list,))`` will give you ``{(1,): 2}``.
           If you want to keep those empty values, you can specify the types in `keep_empty_types`:

           >>> flatten({1: 2, 3: {}}, keep_empty_types=(dict,))
           {(1,): 2, (3,): {}}

       Returns
       -------
       flat_dict : dict
       """

Examples
::::::::

>>> from flatten_dict import flatten
>>> from pprint import pprint
>>> normal_dict = {
...     'a': '0',
...     'b': {
...         'a': '1.0',
...         'b': '1.1',
...     },
...     'c': {
...         'a': '2.0',
...         'b': {
...             'a': '2.1.0',
...             'b': '2.1.1',
...         },
...     },
... }
>>> pprint(flatten(normal_dict))
{('a',): '0',
 ('b', 'a'): '1.0',
 ('b', 'b'): '1.1',
 ('c', 'a'): '2.0',
 ('c', 'b', 'a'): '2.1.0',
 ('c', 'b', 'b'): '2.1.1'}
>>> pprint(flatten(normal_dict, reducer='path'))
{'a': '0',
 'b/a': '1.0',
 'b/b': '1.1',
 'c/a': '2.0',
 'c/b/a': '2.1.0',
 'c/b/b': '2.1.1'}
>>> pprint(flatten(normal_dict, reducer='path', inverse=True))
{'0': 'a',
 '1.0': 'b/a',
 '1.1': 'b/b',
 '2.0': 'c/a',
 '2.1.0': 'c/b/a',
 '2.1.1': 'c/b/b'}
>>> pprint(flatten(normal_dict, reducer='path', max_flatten_depth=2))
{'a': '0',
 'b/a': '1.0',
 'b/b': '1.1',
 'c/a': '2.0',
 'c/b': {'a': '2.1.0', 'b': '2.1.1'}}

The `reducer` parameter supports ``'tuple'``, ``'path'``, ``'underscore'``, ``'dot'`` and `Callable`. We can customize the reducer using a function:

>>> def underscore_reducer(k1, k2):
...     if k1 is None:
...         return k2
...     else:
...         return k1 + "_" + k2
...
>>> pprint(flatten(normal_dict, reducer=underscore_reducer))
{'a': '0',
 'b_a': '1.0',
 'b_b': '1.1',
 'c_a': '2.0',
 'c_b_a': '2.1.0',
 'c_b_b': '2.1.1'}

There is also a factory function `make_reducer()` to help you create customized reducer. The function currently only supports customized delimiter:

>>> from flatten_dict.reducers import make_reducer
>>> pprint(flatten(normal_dict, reducer=make_reducer(delimiter='_')))
{'a': '0',
 'b_a': '1.0',
 'b_b': '1.1',
 'c_a': '2.0',
 'c_b_a': '2.1.0',
 'c_b_b': '2.1.1'}

If we have some iterable (e.g., `list`) in the `dict`, we will normally get this:

>>> flatten({'a': [1, 2, 3], 'b': 'c'})
{('a',): [1, 2, 3], ('b',): 'c'}

If we want to use its indices as keys, then we can use the parameter `enumerate_types`:

>>> flatten({'a': [1, 2, 3], 'b': 'c'}, enumerate_types=(list,))
{('a', 0): 1, ('a', 1): 2, ('a', 2): 3, ('b',): 'c'}

We can even flatten a `list` directly:

>>> flatten([1, 2, 3], enumerate_types=(list,))
{(0,): 1, (1,): 2, (2,): 3}

If there is an empty dict in the values, by default, it will disappear after flattened:

>>> flatten({1: 2, 3: {}})
{(1,): 2}

We can keep the empty dict in the result using ``keep_empty_types=(dict,)``:

>>> flatten({1: 2, 3: {}}, keep_empty_types=(dict,))
{(1,): 2, (3,): {}}

Unflatten
`````````

.. code-block:: python

   def unflatten(d, splitter='tuple', inverse=False):
       """Unflatten dict-like object.

       Parameters
       ----------
       d : dict-like object
           The dict that will be unflattened.
       splitter : {'tuple', 'path', 'underscore', 'dot', Callable}
           The key splitting method. If a Callable is given, the Callable will be
           used to split `d`.
           'tuple': Use each element in the tuple key as the key of the unflattened dict.
           'path': Use `pathlib.Path.parts` to split keys.
           'underscore': Use underscores to split keys.
           'dot': Use underscores to split keys.
       inverse : bool
           Whether you want to invert the key and value before flattening.

       Returns
       -------
       unflattened_dict : dict
       """

Examples
::::::::

>>> from pprint import pprint
>>> from flatten_dict import unflatten
>>> flat_dict = {
...     ('a',): '0',
...     ('b', 'a'): '1.0',
...     ('b', 'b'): '1.1',
...     ('c', 'a'): '2.0',
...     ('c', 'b', 'a'): '2.1.0',
...     ('c', 'b', 'b'): '2.1.1',
... }
>>> pprint(unflatten(flat_dict))
{'a': '0',
 'b': {'a': '1.0', 'b': '1.1'},
 'c': {'a': '2.0', 'b': {'a': '2.1.0', 'b': '2.1.1'}}}
>>> flat_dict = {
...     'a': '0',
...     'b/a': '1.0',
...     'b/b': '1.1',
...     'c/a': '2.0',
...     'c/b/a': '2.1.0',
...     'c/b/b': '2.1.1',
... }
>>> pprint(unflatten(flat_dict, splitter='path'))
{'a': '0',
 'b': {'a': '1.0', 'b': '1.1'},
 'c': {'a': '2.0', 'b': {'a': '2.1.0', 'b': '2.1.1'}}}
>>> flat_dict = {
...     '0': 'a',
...     '1.0': 'b/a',
...     '1.1': 'b/b',
...     '2.0': 'c/a',
...     '2.1.0': 'c/b/a',
...     '2.1.1': 'c/b/b',
... }
>>> pprint(unflatten(flat_dict, splitter='path', inverse=True))
{'a': '0',
 'b': {'a': '1.0', 'b': '1.1'},
 'c': {'a': '2.0', 'b': {'a': '2.1.0', 'b': '2.1.1'}}}

The `splitter` parameter supports ``'tuple'``, ``'path'``, ``'underscore'``, ``'dot'`` and `Callable`. We can customize the reducer using a function:

>>> def underscore_splitter(flat_key):
...     return flat_key.split("_")
...
>>> flat_dict = {
...     'a': '0',
...     'b_a': '1.0',
...     'b_b': '1.1',
...     'c_a': '2.0',
...     'c_b_a': '2.1.0',
...     'c_b_b': '2.1.1',
... }
>>> pprint(unflatten(flat_dict, splitter=underscore_splitter))
{'a': '0',
 'b': {'a': '1.0', 'b': '1.1'},
 'c': {'a': '2.0', 'b': {'a': '2.1.0', 'b': '2.1.1'}}}

There is also a factory function `make_splitter()` to help you create customized splitter. The function currently only supports customized delimiter:

>>> from flatten_dict.splitters import make_splitter
>>> pprint(unflatten(flat_dict, splitter=make_splitter(delimiter='_')))
{'a': '0',
 'b': {'a': '1.0', 'b': '1.1'},
 'c': {'a': '2.0', 'b': {'a': '2.1.0', 'b': '2.1.1'}}}

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/ianlini/flatten-dict",
    "name": "flatten-dict",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*",
    "maintainer_email": "",
    "keywords": "",
    "author": "Ian Lin",
    "author_email": "you@example.com",
    "download_url": "https://files.pythonhosted.org/packages/89/c6/5fe21639369f2ea609c964e20870b5c6c98a134ef12af848a7776ddbabe3/flatten-dict-0.4.2.tar.gz",
    "platform": "",
    "description": "flatten-dict\n============\n.. image:: https://github.com/ianlini/flatten-dict/actions/workflows/main.yml/badge.svg\n   :target: https://github.com/ianlini/flatten-dict/actions\n.. image:: https://img.shields.io/pypi/v/flatten-dict.svg\n   :target: https://pypi.org/project/flatten-dict/\n.. image:: https://img.shields.io/pypi/l/flatten-dict.svg\n   :target: https://github.com/ianlini/flatten-dict/blob/master/LICENSE\n.. image:: https://img.shields.io/github/stars/ianlini/flatten-dict.svg?style=social\n   :target: https://github.com/ianlini/flatten-dict\n\nA flexible utility for flattening and unflattening dict-like objects in Python.\n\n\nIntroduction\n------------\nThis package provides a function ``flatten()`` for flattening dict-like objects in Python 2.7 and 3.5~3.8.\nIt also provides some key joining methods (reducer), and you can choose the reducer you want or even implement your own reducer.\nYou can also invert the resulting flat dict using ``unflatten()``.\n\nInstallation\n------------\n\n.. code-block:: bash\n\n   pip install flatten-dict\n\nDocumentation\n-------------\n\nFlatten\n```````\n\n.. code-block:: python\n\n   def flatten(d, reducer='tuple', inverse=False, enumerate_types=(), keep_empty_types=()):\n       \"\"\"Flatten `Mapping` object.\n\n       Parameters\n       ----------\n       d : dict-like object\n           The dict that will be flattened.\n       reducer : {'tuple', 'path', 'underscore', 'dot', Callable}\n           The key joining method. If a `Callable` is given, the `Callable` will be\n           used to reduce.\n           'tuple': The resulting key will be tuple of the original keys.\n           'path': Use `os.path.join` to join keys.\n           'underscore': Use underscores to join keys.\n           'dot': Use dots to join keys.\n       inverse : bool\n           Whether you want invert the resulting key and value.\n       max_flatten_depth : int\n           Maximum depth to merge.\n       enumerate_types : Sequence[type]\n           Flatten these types using `enumerate`.\n           For example, if we set `enumerate_types` to ``(list,)``,\n           `list` indices become keys: ``{'a': ['b', 'c']}`` -> ``{('a', 0): 'b', ('a', 1): 'c'}``.\n       keep_empty_types : Sequence[type]\n           By default, ``flatten({1: 2, 3: {}})`` will give you ``{(1,): 2}``, that is, the key ``3``\n           will disappear.\n           This is also applied for the types in `enumerate_types`, that is,\n           ``flatten({1: 2, 3: []}, enumerate_types=(list,))`` will give you ``{(1,): 2}``.\n           If you want to keep those empty values, you can specify the types in `keep_empty_types`:\n\n           >>> flatten({1: 2, 3: {}}, keep_empty_types=(dict,))\n           {(1,): 2, (3,): {}}\n\n       Returns\n       -------\n       flat_dict : dict\n       \"\"\"\n\nExamples\n::::::::\n\n>>> from flatten_dict import flatten\n>>> from pprint import pprint\n>>> normal_dict = {\n...     'a': '0',\n...     'b': {\n...         'a': '1.0',\n...         'b': '1.1',\n...     },\n...     'c': {\n...         'a': '2.0',\n...         'b': {\n...             'a': '2.1.0',\n...             'b': '2.1.1',\n...         },\n...     },\n... }\n>>> pprint(flatten(normal_dict))\n{('a',): '0',\n ('b', 'a'): '1.0',\n ('b', 'b'): '1.1',\n ('c', 'a'): '2.0',\n ('c', 'b', 'a'): '2.1.0',\n ('c', 'b', 'b'): '2.1.1'}\n>>> pprint(flatten(normal_dict, reducer='path'))\n{'a': '0',\n 'b/a': '1.0',\n 'b/b': '1.1',\n 'c/a': '2.0',\n 'c/b/a': '2.1.0',\n 'c/b/b': '2.1.1'}\n>>> pprint(flatten(normal_dict, reducer='path', inverse=True))\n{'0': 'a',\n '1.0': 'b/a',\n '1.1': 'b/b',\n '2.0': 'c/a',\n '2.1.0': 'c/b/a',\n '2.1.1': 'c/b/b'}\n>>> pprint(flatten(normal_dict, reducer='path', max_flatten_depth=2))\n{'a': '0',\n 'b/a': '1.0',\n 'b/b': '1.1',\n 'c/a': '2.0',\n 'c/b': {'a': '2.1.0', 'b': '2.1.1'}}\n\nThe `reducer` parameter supports ``'tuple'``, ``'path'``, ``'underscore'``, ``'dot'`` and `Callable`. We can customize the reducer using a function:\n\n>>> def underscore_reducer(k1, k2):\n...     if k1 is None:\n...         return k2\n...     else:\n...         return k1 + \"_\" + k2\n...\n>>> pprint(flatten(normal_dict, reducer=underscore_reducer))\n{'a': '0',\n 'b_a': '1.0',\n 'b_b': '1.1',\n 'c_a': '2.0',\n 'c_b_a': '2.1.0',\n 'c_b_b': '2.1.1'}\n\nThere is also a factory function `make_reducer()` to help you create customized reducer. The function currently only supports customized delimiter:\n\n>>> from flatten_dict.reducers import make_reducer\n>>> pprint(flatten(normal_dict, reducer=make_reducer(delimiter='_')))\n{'a': '0',\n 'b_a': '1.0',\n 'b_b': '1.1',\n 'c_a': '2.0',\n 'c_b_a': '2.1.0',\n 'c_b_b': '2.1.1'}\n\nIf we have some iterable (e.g., `list`) in the `dict`, we will normally get this:\n\n>>> flatten({'a': [1, 2, 3], 'b': 'c'})\n{('a',): [1, 2, 3], ('b',): 'c'}\n\nIf we want to use its indices as keys, then we can use the parameter `enumerate_types`:\n\n>>> flatten({'a': [1, 2, 3], 'b': 'c'}, enumerate_types=(list,))\n{('a', 0): 1, ('a', 1): 2, ('a', 2): 3, ('b',): 'c'}\n\nWe can even flatten a `list` directly:\n\n>>> flatten([1, 2, 3], enumerate_types=(list,))\n{(0,): 1, (1,): 2, (2,): 3}\n\nIf there is an empty dict in the values, by default, it will disappear after flattened:\n\n>>> flatten({1: 2, 3: {}})\n{(1,): 2}\n\nWe can keep the empty dict in the result using ``keep_empty_types=(dict,)``:\n\n>>> flatten({1: 2, 3: {}}, keep_empty_types=(dict,))\n{(1,): 2, (3,): {}}\n\nUnflatten\n`````````\n\n.. code-block:: python\n\n   def unflatten(d, splitter='tuple', inverse=False):\n       \"\"\"Unflatten dict-like object.\n\n       Parameters\n       ----------\n       d : dict-like object\n           The dict that will be unflattened.\n       splitter : {'tuple', 'path', 'underscore', 'dot', Callable}\n           The key splitting method. If a Callable is given, the Callable will be\n           used to split `d`.\n           'tuple': Use each element in the tuple key as the key of the unflattened dict.\n           'path': Use `pathlib.Path.parts` to split keys.\n           'underscore': Use underscores to split keys.\n           'dot': Use underscores to split keys.\n       inverse : bool\n           Whether you want to invert the key and value before flattening.\n\n       Returns\n       -------\n       unflattened_dict : dict\n       \"\"\"\n\nExamples\n::::::::\n\n>>> from pprint import pprint\n>>> from flatten_dict import unflatten\n>>> flat_dict = {\n...     ('a',): '0',\n...     ('b', 'a'): '1.0',\n...     ('b', 'b'): '1.1',\n...     ('c', 'a'): '2.0',\n...     ('c', 'b', 'a'): '2.1.0',\n...     ('c', 'b', 'b'): '2.1.1',\n... }\n>>> pprint(unflatten(flat_dict))\n{'a': '0',\n 'b': {'a': '1.0', 'b': '1.1'},\n 'c': {'a': '2.0', 'b': {'a': '2.1.0', 'b': '2.1.1'}}}\n>>> flat_dict = {\n...     'a': '0',\n...     'b/a': '1.0',\n...     'b/b': '1.1',\n...     'c/a': '2.0',\n...     'c/b/a': '2.1.0',\n...     'c/b/b': '2.1.1',\n... }\n>>> pprint(unflatten(flat_dict, splitter='path'))\n{'a': '0',\n 'b': {'a': '1.0', 'b': '1.1'},\n 'c': {'a': '2.0', 'b': {'a': '2.1.0', 'b': '2.1.1'}}}\n>>> flat_dict = {\n...     '0': 'a',\n...     '1.0': 'b/a',\n...     '1.1': 'b/b',\n...     '2.0': 'c/a',\n...     '2.1.0': 'c/b/a',\n...     '2.1.1': 'c/b/b',\n... }\n>>> pprint(unflatten(flat_dict, splitter='path', inverse=True))\n{'a': '0',\n 'b': {'a': '1.0', 'b': '1.1'},\n 'c': {'a': '2.0', 'b': {'a': '2.1.0', 'b': '2.1.1'}}}\n\nThe `splitter` parameter supports ``'tuple'``, ``'path'``, ``'underscore'``, ``'dot'`` and `Callable`. We can customize the reducer using a function:\n\n>>> def underscore_splitter(flat_key):\n...     return flat_key.split(\"_\")\n...\n>>> flat_dict = {\n...     'a': '0',\n...     'b_a': '1.0',\n...     'b_b': '1.1',\n...     'c_a': '2.0',\n...     'c_b_a': '2.1.0',\n...     'c_b_b': '2.1.1',\n... }\n>>> pprint(unflatten(flat_dict, splitter=underscore_splitter))\n{'a': '0',\n 'b': {'a': '1.0', 'b': '1.1'},\n 'c': {'a': '2.0', 'b': {'a': '2.1.0', 'b': '2.1.1'}}}\n\nThere is also a factory function `make_splitter()` to help you create customized splitter. The function currently only supports customized delimiter:\n\n>>> from flatten_dict.splitters import make_splitter\n>>> pprint(unflatten(flat_dict, splitter=make_splitter(delimiter='_')))\n{'a': '0',\n 'b': {'a': '1.0', 'b': '1.1'},\n 'c': {'a': '2.0', 'b': {'a': '2.1.0', 'b': '2.1.1'}}}\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A flexible utility for flattening and unflattening dict-like objects in Python.",
    "version": "0.4.2",
    "project_urls": {
        "Homepage": "https://github.com/ianlini/flatten-dict",
        "Repository": "https://github.com/ianlini/flatten-dict"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "43f5ee39c6e92acc742c052f137b47c210cd0a1b72dcd3f98495528bb4d27761",
                "md5": "6419e84c5cb5d5dca732eae85e3ece4f",
                "sha256": "7e245b20c4c718981212210eec4284a330c9f713e632e98765560e05421e48ad"
            },
            "downloads": -1,
            "filename": "flatten_dict-0.4.2-py2.py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "6419e84c5cb5d5dca732eae85e3ece4f",
            "packagetype": "bdist_wheel",
            "python_version": "py2.py3",
            "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*",
            "size": 9656,
            "upload_time": "2021-08-08T09:56:54",
            "upload_time_iso_8601": "2021-08-08T09:56:54.313653Z",
            "url": "https://files.pythonhosted.org/packages/43/f5/ee39c6e92acc742c052f137b47c210cd0a1b72dcd3f98495528bb4d27761/flatten_dict-0.4.2-py2.py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "89c65fe21639369f2ea609c964e20870b5c6c98a134ef12af848a7776ddbabe3",
                "md5": "897952161d3ef40807de444610521f01",
                "sha256": "506a96b6e6f805b81ae46a0f9f31290beb5fa79ded9d80dbe1b7fa236ab43076"
            },
            "downloads": -1,
            "filename": "flatten-dict-0.4.2.tar.gz",
            "has_sig": false,
            "md5_digest": "897952161d3ef40807de444610521f01",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*",
            "size": 10362,
            "upload_time": "2021-08-08T09:56:51",
            "upload_time_iso_8601": "2021-08-08T09:56:51.455294Z",
            "url": "https://files.pythonhosted.org/packages/89/c6/5fe21639369f2ea609c964e20870b5c6c98a134ef12af848a7776ddbabe3/flatten-dict-0.4.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2021-08-08 09:56:51",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ianlini",
    "github_project": "flatten-dict",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "flatten-dict"
}
        
Elapsed time: 3.84036s