Home > Software design >  How can i use dictionary comprehensions where nested dict or list may occur
How can i use dictionary comprehensions where nested dict or list may occur

Time:09-17

How can I use dictionary comprehension for values that are literals or list

Right now I'm able to iterate through a nested dictionary and get as a result dict with nested values, but I would like to include in the output dict, list, and literals (int, str)

Here is my example ( I know that isinstance is not needed here)

nested_dict = {'first':{'a':1}, 'second':{'b':2}, 'third': 3, 'fourth': [1, 2, 3, 4]}

float_dict = {
    outer_k: { float(inner_v)
        for (inner_k, inner_v) in outer_v.items()}
            for (outer_k, outer_v) in nested_dict.items()
                if isinstance(outer_v, dict) 
}

print(float_dict)

Expected output:

{'first': {'a': 1.0}, 'second': {'b': 2.0}, 'third': 3.0, 'fourth': [1.0, 2.0, 3.0, 4.0]}

CodePudding user response:

It's not (reasonably) possible using a single comprehension, you want a recursive function like this:

def floatify(v):
    if isinstance(v, list):
        return list(map(floatify, v))
    if isinstance(v, dict):
        return {k: floatify(_v) for k, _v in v.items()}
    return float(v)
>>> floatify(nested_dict)
{'first': {'a': 1.0}, 'second': {'b': 2.0}, 'third': 3.0, 'fourth': [1.0, 2.0, 3.0, 4.0]}

Note that you can make this function even more generic:

def anyify(v, f):
    if isinstance(v, list):
        return [anyify(_v, f) for _v in v]
    if isinstance(v, dict):
        return {k: anyify(_v, f) for k, _v in v.items()}
    return f(v)

anyify(nested_dict, float)

CodePudding user response:

Or without recursion you could kinda make it in one-liner:

{outer_k: ({inner_k: float(inner_v) for (inner_k, inner_v) in outer_v.items()} if isinstance(outer_v, dict) else ([float(i) for i in outer_v] if isinstance(outer_v, list) else float(outer_v))) for (outer_k, outer_v) in nested_dict.items()}

Ex:

nested_dict = {'first':{'a':1}, 'second':{'b':2}, 'third': 3, 'fourth': [1, 2, 3, 4]}

float_dict = {outer_k: ({inner_k: float(inner_v) for (inner_k, inner_v) in outer_v.items()} if isinstance(outer_v, dict) else ([float(i) for i in outer_v] if isinstance(outer_v, list) else float(outer_v))) for (outer_k, outer_v) in nested_dict.items()}
print(float_dict)

Output:

{'first': {'a': 1.0}, 'second': {'b': 2.0}, 'third': 3.0, 'fourth': [1.0, 2.0, 3.0, 4.0]}

CodePudding user response:

Here is a solution that uses a queue. By taking advantage of the mutability of dicts and lists, we can enqueue those objects (even inner ones and even how deeply nested) and still be able to update the source data. This will traverse and enqueue each inner element of the data. If the element is an int, it will convert it to float.

import copy

nested_dict = {'first':{'a':1}, 'second':{'b':2}, 'third': 3, 'fourth': [4, {"fifth": 5}, 6, [{"sixth": [7, 8]}, 9], 10]}

float_dict = copy.deepcopy(nested_dict)

queue = [float_dict]
while queue:
    data = queue.pop()
    items = data.items() if isinstance(data, dict) else enumerate(data)
    for key, value in items:
        if isinstance(value, int):
            data[key] = float(value)
        elif isinstance(value, (dict, list)):
            queue.append(value)

print(float_dict)

Output

{'first': {'a': 1.0}, 'second': {'b': 2.0}, 'third': 3.0, 'fourth': [4.0, {'fifth': 5.0}, 6.0, [{'sixth': [7.0, 8.0]}, 9.0], 10.0]}
  • Related