1

I am trying to delete a dictionary item nested within a list, in a dict.
After I del the object, the modified dictionary will contain an empty dictionary: {} in the place of the deleted object.
Here is the code I am using:

json_dict = {"top_key": "top_value", "bottom_key": [{"list_dict": "list_dict_value"},{"list_dict1": "list_dict_value1"}]}

print("initial:", json_dict)

def delete(list_dict):
    for i in json_dict["bottom_key"]:
        if list_dict in i:
            del i[list_dict]


delete("list_dict")
print("final:", json_dict)  

The final print will return:
final: {'bottom_key': [{}, {'list_dict1': 'list_dict_value1'}], 'top_key': 'top_value'} (pw-retriever) simon@[pw-retriever](fix_del_ls)

I am trying to find a way to remove the {} in addition to the key:value pair, in one go.

edit: an explanation as to what the heck is going on would also be highly appreciated.

Jay Jung
  • 1,805
  • 3
  • 23
  • 46

2 Answers2

2

You can do the following:

for i in json_dict["bottom_key"][:]:  # important: iterate a shallow copy
    if list_dict in i:
        json_dict["bottom_key"].remove(i)

However, since removing from a list is O(N) and you might have to remove multiple elements, you might consider just rebuilding it from scratch in one go:

json_dict["bottom_key"] = [d for d in json_dict["bottom_key"] if list_dict not in d]
user2390182
  • 72,016
  • 6
  • 67
  • 89
  • @PM2Ring Good to know :) But sometimes someone else has just posted an answer too similar to keep mine. Or sth has come up preventing you from polishing your answer so you'd rather remove it than leave it as is. – user2390182 Oct 14 '17 at 12:55
  • @schwobaseggl Regarding the "# important:" comment: are you simply pointing out that you've made a shallow copy? – Jay Jung Oct 14 '17 at 13:02
  • 1
    Yup. Without the `[:]` slice the behaviour can turn ugly as you are removing from the collection that you are iterating. – user2390182 Oct 14 '17 at 13:04
  • 1
    @simonsays As I said above, it's not safe to remove stuff from a list that you're iterating over in the forward direction. It's like sawing off a tree branch that you're sitting on. If you cut on the wrong side, bad things happen. ;) Play around with some examples and you'll see what I mean. And you can see some examples here: [Remove items from a list while iterating](https://stackoverflow.com/questions/1207406/remove-items-from-a-list-while-iterating) – PM 2Ring Oct 14 '17 at 13:07
0

Constructing further on basis of your structure, del using the index of the dict, like follows :

def delete(list_dict):
    for i,ele in enumerate(json_dict["bottom_key"][:]) :
        if list_dict in ele:
            del json_dict["bottom_key"][i]

#driver values :

IN : initial: {'top_key': 'top_value', 'bottom_key': [{'list_dict': 'list_dict_value'}, {'list_dict1': 'list_dict_value1'}]}

>>> delete("list_dict")

OUT : final: {'top_key': 'top_value', 'bottom_key': [{'list_dict1': 'list_dict_value1'}]}

EDIT : schwobaseggl's idea of reconstructing the dictionary is better than deleting the elements as the previous one can lead to logical mistakes.

Kaushik NP
  • 6,733
  • 9
  • 31
  • 60
  • This won't work properly if there are more instances to be deleted. You are removing stuff while iterating... the indexes won't match anymore. – user2390182 Oct 14 '17 at 12:49
  • @schwobaseggl, true. As you mention, using a shallow copy is better. Thanks for pointing it out. – Kaushik NP Oct 14 '17 at 12:50