5

Using Python, I need to delete all objects in JSON array that have specific value of 'name' key. However, I can't do that from a loop.

Imaging I want to delete all items having 'bad' as name in the following input:

{
  'myArray' : [
    {
      'name' : 'good',
      'value' : '1'
    },
    {
      'name' : 'bad',
      'value' : '2'
    }
  ]
}

So I use the following Python test case:

myData = {'myArray': [{'name': 'good', 'value': '1'}, {'name': 'bad', 'value': '2'}]}

for a in myData['myArray']:
  if (a['name'] =='bad'):
    del a

print(json.dumps(myData))

And I see that the myData is not changed.

I assume this is because I try to delete an iterator of a loop, that might be considered as risky action by interpreter, however no runtime error or warning is reported by Python.

What's the recommended approach in this case?

Thanks!

Dmytro
  • 216
  • 1
  • 4
  • 14
  • "I assume this is because I try to delete an iterator of a loop, that might be considered as risky action by interpreter, however no runtime error or warning is reported by Python" You are not deleting the iterator. In fact, you don't have access to the iterator. You are simply doing `del` on `a`, which is the variable that the result of (implicitely) calling `next` on the (invisible) iterator is assigned to. So you delete the variable, but then on the next iteration, that variable is simply re-created. You want to *mutate your collection*, but you probably shouldn't *while iterating* – juanpa.arrivillaga Sep 04 '18 at 21:43
  • Use a (nested) dict/list comprehension. Never try to delete elements of an object while iterating over it. – smci Sep 04 '18 at 21:44
  • @smci or just a for-loop. – juanpa.arrivillaga Sep 04 '18 at 21:46
  • Related: [Remove element from JSON list...](https://stackoverflow.com/a/38547020/202229) – smci Sep 04 '18 at 21:48
  • juanpa.arrivillaga, thank you, your explanation "that variable is simply re-created" brings the light here. I see one workaround: copy all elements except 'bad' to newly created collection, and then substitute it instead of old one. Not optimal solution but I'll use it if no easier approach is suggested by someone. – Dmytro Sep 04 '18 at 21:52
  • @Dmytro that *is* an optimal solution, because it will run in O(N) time vs O(N^2) if you delete from the list. Using a list comprehension here would be idiomatic, too, and that is very expressive/readable. You coudl also use an equivalent for-loop, but in this case, `[x for x in myData['myArray'] if x['name'] !='bad']` is very simple and easy. – juanpa.arrivillaga Sep 04 '18 at 21:55
  • Ok, makes sense. Thanks for the explanation! – Dmytro Sep 04 '18 at 22:03

4 Answers4

3

One of approaches from Remove element from list when using enumerate() in python - a loop over a copy of the list referred as [:] - works too:

for a in myData['myArray'][:]:
  if (a['name'] == u'bad'):
     myData['myArray'].remove(a)

Thanks everyone!

Dmytro
  • 216
  • 1
  • 4
  • 14
1

Use a (nested) dict/list comprehension. Never try to delete elements of an object while iterating over it

>>> [x for x in myData['myArray'] if x['name'] != 'bad']
[{'name': 'good', 'value': '1'}]

Assign the result to myData['myArray'], or whatever you want.

smci
  • 32,567
  • 20
  • 113
  • 146
0

You can use the list comprehension. Below is the reference.

new_list =  [obj for obj in myData['myArray'] if(obj['name'] != 'bad')] 
print new_list
PARMESH
  • 98
  • 6
0
myData = {'myArray': [{'name': 'good', 'value': '1'}, {'name': 'bad', 'value': '2'}]}

myData_clean = [x for x in myData['myArray'] if x['name'] !='bad']
myData_clean = {'myArray':myData_clean}
print(myData_clean)

output:

{'myArray': [{'name': 'good', 'value': '1'}]}
Pedro
  • 355
  • 4
  • 18