-3

I have JSON file (test.json) that has a list:

[
    {
        "Action": "ADD",
        "Properties": {
            "Type": "New",
            "Value": "List"
        }
    },
    {
        "Action": "REMOVE",
        "Properties": {
            "Type": "New",
            "Value": "Image"
        }
    },
    {
        "Action": "ADD",
        "Properties": {
            "Type": "New",
            "Value": "Text"
        }
    }
]

I need to iterate through the list and delete the key (item) that contains 'REMOVE' , i.e. item['Action'] == "REMOVE".

It should look like this after deletion:

[
    {
        "Action": "ADD",
        "Properties": {
            "Type": "New",
            "Value": "List"
        }
    },
    {
        "Action": "ADD",
        "Properties": {
            "Type": "New",
            "Value": "Text"
        }
    }
]

I use this to print the item. How do I delete the item?

with open('test.json') as json_data:
    data = json.load(json_data)
    for item in data:
        if item['Action'] == "REMOVE":
            print item
Andrej Kesely
  • 168,389
  • 15
  • 48
  • 91
cloudy
  • 1
  • Possible duplicate of [How to remove items from a list while iterating?](https://stackoverflow.com/questions/1207406/how-to-remove-items-from-a-list-while-iterating) – Ishan Srivastava Jul 19 '18 at 21:38
  • @YanOrestes Why is this posted as a comment on the question rather than my answer? At any rate, my answer explicitly does a `break` after the `del`, and then has a whole paragraph explaining why. – abarnert Jul 19 '18 at 21:39
  • None of the solutions worked. I tried with ENUMERATE and also tried with APPEND but the key that has 'REMOVE' is not being deleted. Nothing is getting deleted – cloudy Jul 20 '18 at 14:22

4 Answers4

3

If you need to delete the item in-place, you need its index.

But that's exactly what enumerate is for:

with open('test.json') as json_data:
    data = json.load(json_data)
    for index, item in enumerate(data):
        if item['Action'] == "REMOVE":
            del data[index]
            break

Note that this will only work if you're definitely only removing one value. Because when you del a value from a list, everything after it shifts up one slot, and if you're still trying to iterate over the list, at best you end up skipping one value in your loop, and at worst you make a huge mess. There are various ways around that if it comes up, but if you don't need that, don't add the complexity.


If you don't need to make the change in-place for some reason, unless data is huge, it's usually better to make a new list, with all the values you want to keep:

with open('test.json') as json_data:
    data = json.load(json_data)
    new_data = []
    for item in data:
        if item['Action'] != "REMOVE":
            new_data.append(item)

… which can you condense into a simple comprehension:

with open('test.json') as json_data:
    data = json.load(json_data)
    new_data = [item for item in data if item['Action'] != "REMOVE"]

Either way, notice that, unlike the del, this one automatically works if there are multiple values that match "REMOVE", with no tricks needed.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • 1
    In python, appending the item to the new list will just be referring back to the original item in memory (rather than copying it), so this isn't as memory-inefficient as it might first seem. – JMAA Jul 19 '18 at 21:35
  • @JMAA Sure. And, more importantly, not as time-inefficient as it might seem if you were coming from, say, C++. (Also, the `del` version is _less_ time-inefficient than it might seem, because `del lst[i]` is linear time.) But do you think the answer needs to get into any of that? – abarnert Jul 19 '18 at 21:37
  • I think the answer is good as-is. Just thought I'd add the comment for unintrusive-completeness :) – JMAA Jul 19 '18 at 21:39
  • @JMAA OK, cool; just making sure. (I _usually_ have the problem of including too much irrelevant stuff, but occasionally I err in the other direction too…) – abarnert Jul 19 '18 at 21:40
  • @abarnert Thanks, but unfortunately none of the solutions worked. I tried with ENUMERATE and also tried with APPEND but the key that has 'REMOVE' is not being deleted. Nothing is getting deleted. – cloudy Jul 20 '18 at 13:38
2

You should use a list comprehension whenever you need to filter a list:

with open('test.json') as json_data:
    data = json.load(json_data)
    filtered_data = [item for item in data if item['Action'] != 'REMOVE']
yyyyyyyan
  • 410
  • 2
  • 7
  • Thanks, but unfortunately this approach did not work either. the key that has 'REMOVE' is not being deleted. Nothing is getting deleted. – cloudy Jul 20 '18 at 13:40
0

I ended up using this:

with open('test.json') as json_data:
    data = json.load(json_data)
    for index, item in enumerate(data):
        if item['Action'] == "REMOVE":
            del( data[index] )
            with open('test.json', "w") as outfile:
                outfile.write(json.dumps(data, indent=4))
cloudy
  • 1
-1
data = [x for x in json_data if not x['ACTION'] == 'REMOVE']

another way to get a new list with only the desired items.

Ishan Srivastava
  • 1,129
  • 1
  • 11
  • 29
  • this just throws an error: Traceback (most recent call last): File "test.py", line 16, in data = [x for x in json_data if not x['ACTION'] == 'REMOVE'] TypeError: string indices must be integers, not str – cloudy Jul 20 '18 at 13:46
  • @cloudy make sure the `json_data` is the object that you read json from which will be a list of dicts, not inside those dicts – Ishan Srivastava Jul 20 '18 at 17:00