Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterate over nested lists and dictionaries

Tags:

python

loops

I need to iterate over nested lists and dictionaries and replace every integer trough an hex string. Such an element could for example look like this:

element = {'Request': [16, 2], 'Params': ['Typetext', [16, 2], 2], 'Service': 'Servicetext', 'Responses': [{'State': 'Positive', 'PDU': [80, 2, 0]}, {}]}

After after applying the function, it should look like this:

element = {'Request': ['0x10', '0x02'], 'Params': ['Typetext', ['0x10', '0x02'], '0x02'], 'Service': 'Servicetext', 'Responses': [{'State': 'Positive', 'PDU': ['0x50', '0x02', '0x00']}, {}]}

I've already found a function, to iterate over such nested iterables http://code.activestate.com/recipes/577982-recursively-walk-python-objects/. Adapted to python 2.5 this function looks like this:

string_types = (str, unicode)
iteritems = lambda mapping: getattr(mapping, 'iteritems', mapping.items)()

def objwalk(obj, path=(), memo=None):
    if memo is None:
        memo = set()
    iterator = None
    if isinstance(obj, dict):
        iterator = iteritems
    elif isinstance(obj, (list, set)) and not isinstance(obj, string_types):
        iterator = enumerate
    if iterator:
        if id(obj) not in memo:
            memo.add(id(obj))
            for path_component, value in iterator(obj):
                for result in objwalk(value, path + (path_component,), memo):
                    yield result
            memo.remove(id(obj))
    else:
        yield path, obj

But the problem with this function is, that it returns tuple elements. And those can't be edited. Can you help me to implement a function I need?

Best regards wewa

like image 346
wewa Avatar asked Nov 03 '22 20:11

wewa


1 Answers

The function doesn't just return tuple elements; it returns the path to any item in the nested structure, plus it's value. You can use that path to get at the value and change it:

for path, value in objwalk(element):
    if isinstance(value, int):
        parent = element
        for step in path[:-1]:
            parent = parent[step]
        parent[path[-1]] = hex(value)

So, for every value that is an integer, use the path to find the parent of that value, then replace the current value with it's hex equivalent.

The output you get from the above method:

>>> element
{'Params': ['Typetext', ['0x10', '0x2'], '0x2'], 'Request': ['0x10', '0x2'], 'Responses': [{'State': 'Positive', 'PDU': ['0x50', '0x2', '0x0']}, {}], 'Service': 'Servicetext'}
like image 77
Martijn Pieters Avatar answered Nov 15 '22 03:11

Martijn Pieters