2

I have a code that uses the NestedDict class here: How can I access a deeply nested dictionary using tuples?. "I have a fully working example based on @JCash's answer:"

There are two things I would like to do with it that are causing me trouble. First, I would like to delete one of it's elements if the value of that element is zero. second, if an element is an empty dictionary because all the entries of that dictionary were deleted, I would like to delete the empty dictionary.

Using the class sited above, an example is the following:

my_tuple = (0, 1, 0, 0, 0, 1, 0, 0)
d = NestedDict()
print d
d[my_tuple] = 4
print d

#del d[my_tuple]

del d[0][1][0][0][0][1][0][0]
del d[0][1][0][0][0][1][0]
del d[0][1][0][0][0][1]
del d[0][1][0][0][0]
del d[0][1][0][0]
del d[0][1][0]
del d[0][1]
del d[0]

print d

The long list of del's is necessary in order to get rid of the multiple levels of nesting. the commented out del statement (which gives a key-error) is what I would like to implement, with a tuple of arbitrary length.

Deleting the intermediate levels shouldn't be hard once I figure out how to delete the first. I already know what I want to delete, and I can test for empty dictionaries with: if (dictionary entry) == {})

Any ideas?

Edit: Output is:

{}
{0: {1: {0: {0: {0: {1: {0: {0: 4}}}}}}}}
{}
Community
  • 1
  • 1
juggler
  • 319
  • 1
  • 5
  • 16
  • 1
    Please post the output of `print d` – inspectorG4dget Jan 27 '14 at 19:50
  • I think it should be, just not sure how, in this case. – juggler Jan 27 '14 at 19:57
  • if you just `del d[0]`, it will delete everything nested into `d[0]`... – roippi Jan 27 '14 at 19:59
  • sure. my bad. my actual structure is much more complicated than what I posted. I need to delete layer by layer, testing whether each layer is empty prior to deleting it. I could edit the question again.. – juggler Jan 27 '14 at 20:01
  • By asking to delete the entry that lives at the index given by `[0][1][0][0][0][1][0][0]` you might end up with an empty `dict` at that level of nesting. This does not necessarily mean than all of the parent levels in the hierarchy should be deleted... it could be the case that having an empty `dict` as the eventual "leaf" of one part of the hierarchy is the correct behavior. It certainly seems better to leave everything, including an empty dict, than to try to walk back up the hierarchy and delete any sub-nestings that only have empty dicts. – ely Jan 27 '14 at 20:02
  • A simple solution that I may adopt is to just set the value of a given entry to zero. then, once all entries have been updated (there may be many zeroes throughout the dictionary), create a new dictionary by iterating through the previous one and creating an entry in the new one for each non-zero entry in the old. just deleting from the old one would seem more elegant though. – juggler Jan 27 '14 at 20:12

1 Answers1

4

Made a function deepdelete which takes a list of keys and recursively deletes the leaf, followed by any branch dictionaries that are now empty:

def deepdelete(branch, keys):
    if len(keys) > 1:                                  # not at the leaf
        empty = deepdelete(branch[keys[0]], keys[1:])  # recursion
        if empty:                                      
            del branch[keys[0]]                        # delete branch
    else:                                              # at the leaf
        del branch[keys[0]]                            # delete the leaf
    return len(branch) == 0                            # could return len

deepdelete(d, delkeys)

Passing in the dictionary you gave as example:

d = {0: {1: {0: {0: {0: {1: {0: {0: 4}}}}}}}}
deepdelete(d, (0, 1, 0, 0, 0, 1, 0, 0))

Outputs:

{}

Passing in a more interesting dictionary with other branches:

d = {0: {1: {0: {0: {0: {1: {0: {0: 4}}, 'no_delete': 2}, 'other_data': 3}, 'keep_me': 4}, 'special': 4}, 'preserve': 1}, 'important': 50}
deepdelete(d, (0, 1, 0, 0, 0, 1, 0, 0))

Outputs:

{0: {'preserve': 1, 1: {0: {0: {0: {'no_delete': 2}, 'other_data': 3}, 'keep_me': 4}, 'special': 4}}, 'important': 50}
mhlester
  • 22,781
  • 10
  • 52
  • 75
  • ok, this may be brilliant, but I have a problem. I included your code in a new file, then put in your two line first example and tried to run it. it gives me `IndentationError: unexpected unindent ` for the line: `d = {0: {1: {0: {0: {0: {1: {0: {0: 4}}}}}}}}`. I even put the def inside a class, same problem. I'd put my exact code, but it doesn't fit in the comment. could you include, please, the simplest code that will allow me to test this answer? I'm sure I can put your def in another file and import it, but I'd like to know the simplest way of doing it. thank's. – juggler Jan 28 '14 at 16:51
  • I was lazy.. some answers here? [link](http://stackoverflow.com/questions/10239668/indentationerror-unexpected-unindent-why) – juggler Jan 28 '14 at 17:13
  • @juggler, Ha, yeah I added the try temporarily, but then didn't fully remove it before posting the answer. Good catch; try now. – mhlester Jan 28 '14 at 17:30
  • oh, you mean the try isn't necessary? I didn't think of that. – juggler Jan 28 '14 at 17:58
  • you can clear something else up for me though.. it looks like each time you re-enter the recursion (empty = deepde..), you are sending in a dictionary, in this case branch[keys[0]]. this gets shorter till you get to the bottom. now, at first glance it seems like you're deleting from this alternate structure, which has nothing to do with the original dictionary. – juggler Jan 28 '14 at 17:59
  • -is what is happening that branch[keys[0]] is like a "picture", a representation of that section of the original dictionary, the way you're telling python what part of the original dictionary you want to do something with? (in this case, delete it?) notice that you haven't put .copy() anywhere.. so this could be considered a pointer to that part of the dictionary. – juggler Jan 28 '14 at 18:00
  • yes, it is only ever working on the original dictionary, sending pointers to the sub-dictionaries, but modifying one modifies all – mhlester Jan 28 '14 at 18:01
  • brilliant. so elegant. – juggler Jan 28 '14 at 18:42