Delete dict and subdict items of some name

Oscar Benjamin oscar.j.benjamin at gmail.com
Mon Dec 17 18:44:53 EST 2012


On 17 December 2012 23:08, MRAB <python at mrabarnett.plus.com> wrote:
> On 2012-12-17 22:00, Dave Angel wrote:
>> On 12/17/2012 04:33 PM, Mitya Sirenef wrote:
>>> On 12/17/2012 01:30 PM, Tim Chase wrote:
>>>> On 12/17/12 11:43, Mitya Sirenef wrote:
>>>>> On 12/17/2012 12:27 PM, Gnarlodious wrote:
>>>>>>
>>>>>> Hello. What I want to do is delete every dictionary key/value
>>>>>> of the name 'Favicon' regardless of depth in subdicts, of which
>>>>>> there are many. What is the best way to do it?
>>>>>
>>>>> Something like this should work:
>>>>>
>>>>> def delkey(d, key):
>>>>>       if isinstance(d, dict):
>>>>>           if key in d: del d[key]
>>>>>           for val in d.values():
>>>>>               delkey(val, key)
>>>>
>>>> Unless you have something hatefully recursive like
>>>>
>>>>    d = {}
>>>>    d["hello"] = d
>>>>
>>>> :-)
>>>
>>>
>>> True -- didn't think of that..!
>>>
>>> I guess then adding a check 'if val is not d: delkey(val, key)'
>>> would take care of it?
>>>
>> No, that would only cover the self-recursive case.  If there's a dict
>> which contains another one, which contains the first, then the recursion
>> is indirect, and much harder to check for.
>>
>> Checking reliably for arbitrary recursion patterns is tricky, but
>> do-able.  Most people degenerate into just setting an arbitrary max
>> depth.  But I can describe two approaches to this kind of problem.
>>
> Wouldn't a set of the id of the visited objects work?

Of course it would. This is just a tree search.

Here's a depth-first-search function:

def dfs(root, childfunc, func):
    '''depth first search on a tree
    calls func(node) once for each node'''
    visited = set()
    visiting = OrderedDict()
    visiting[id(root)] = it = iter([root])

    while True:
        try:
            node = next(it)
        except StopIteration:
            try:
                node, it = visiting.popitem()
            except KeyError:
                return
        key = id(node)
        if isinstance(node, dict) and key not in visited:
            func(node)
            visiting[key] = it = iter(childfunc(node))
            visited.add(key)

Now you can do:

dfs(my_dict_tree, lambda x: x.pop('Favicon', None))


Although I wouldn't bother with the above unless I had some reason to
expect possible cycles.


Oscar



More information about the Python-list mailing list