3
\$\begingroup\$

I have a value test-1 and a list of keys as below:

[
  ["initial", "short_title"],
  ["later", "datasets", "item_okmiwt"],
  ["general_title"]
]

I wanted the resulting dictionary like this:

{'initial': {'short_title': 'test-1'}, 'later': {'datasets': {'item_okmiwt': 'test-1'}}, 'general_title': 'test-1'}

I have written the following code for implementing the above result:

def set_copy_to_attr(value, copy_to_attr):
    """Method to copy value to copy_to config."""

    def build_nested_dict(element, result={}):
        if len(element) == 1:
            result[element[-1]] = pid_value
            return result
        else:
            for el in element:
                result[el] = {}
                element.remove(el)
                build_nested_dict(element, result[el])

    for _element in copy_to_attr:
        _dict = build_nested_dict(_element)

    if _dict:
        return _dict

I am getting the desired result, Is this approach can be optimized more?

\$\endgroup\$

1 Answer 1

5
\$\begingroup\$

Broadly: this kind of dictionary soup is a problem, and is often evidence of inadequate domain modelling and deserialisation. But you haven't shown enough of your actual application to say more.

Two things will slow you down: mutating element via .remove(), and recursing. Python is bad at recursing, and for input of sufficient depth this will easily blow the stack.

Add PEP484 type hints - even though, since this is dictionary soup, typing is made more difficult.

Rather than _dict (making it look like a private), typically to avoid Python keywords, the underscore is a suffix i.e. dict_.

Suggested

from pprint import pprint
from typing import Any, Iterable


def set_copy_to_attr(
    value: Any,
    copy_to_attr: Iterable[Iterable[Any]],
) -> dict:
    dict_ = {}

    for *values, leaf in copy_to_attr:
        nested = dict_
        for v in values:
            nested[v] = nested = {}
        nested[leaf] = value

    return dict_


def test() -> None:
    copy_to_attr = [
      ["initial", "short_title"],
      ["later", "datasets", "item_okmiwt"],
      ["general_title"]
    ]

    copied = set_copy_to_attr('test-1', copy_to_attr)
    pprint(copied)


if __name__ == '__main__':
    test()

Output

{'general_title': 'test-1',
 'initial': {'short_title': 'test-1'},
 'later': {'datasets': {'item_okmiwt': 'test-1'}}}
\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the suggestions, for more context, the logic is to add metadata on the basis of some schema config and it is for showing some default values in the UI. \$\endgroup\$
    – ParthS007
    Aug 24, 2022 at 12:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.