1

I want to remove the values I don't need from an existing json file:

{ "items": [ { "id": "abcd", "h": 2, "x": 0, "level": 4 }, { "id": "dfgg", "h": 7, "x": 5, "level": 30 } ] }

I've tried to remove the values in place but get 'dictionary changed size during iteration'.

with open('inventory2.json', 'r') as inf:
    data = json.load(inf)
    inf.close()

    keysiwant = ['x', 'h']
    for dic in data['items']:
        for k, v in dic.items():
            if k not in keysiwant:
                dic.pop(k, None)
Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
Scott
  • 21
  • 2
  • 8
  • Possible duplicate of [How to avoid "RuntimeError: dictionary changed size during iteration" error?](https://stackoverflow.com/questions/11941817/how-to-avoid-runtimeerror-dictionary-changed-size-during-iteration-error) – Patrick Artner Jan 21 '19 at 19:31

2 Answers2

3

Problem: dict.items() in python 3 is just a view - not a copy of the dict's items - you cannot change it while iterating.

You can however put the dict.items() iterator into a list() (which copies it and decouples it from the dict that way) - you can then iterate over the copy of the dict.items() instead:

import json

t = """{ "items": [ { "id": "abcd", "h": 2, "x": 0, "level": 4 }, 
                    { "id": "dfgg", "h": 7, "x": 5, "level": 30 } ] }"""

data = json.loads(t)   # loads is better for SO-examples .. it makes it a mcve
keysiwant = ['x', 'h']
for dic in data['items']:
    for k, v in list(dic.items()):
        if k not in keysiwant:
            dic.pop(k, None)

print(data) 

Output:

{'items': [{'h': 2, 'x': 0}, {'h': 7, 'x': 5}]}

More on python2/python3 dict.items(): in this answer to What is the difference between dict.items() and dict.iteritems()?

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
0

Please try this. It uses fewer iterations because it filters out keys first, before sending them to pop/remove. Also, it uses keys only (list(dic)) instead of tuple key/value.

import json

t = """{ "items": [ { "id": "abcd", "h": 2, "x": 0, "level": 4 },
                    { "id": "dfgg", "h": 7, "x": 5, "level": 30 } ] }"""

data = json.loads(t)
keysiwant = ["x", "h"]

for dic in data["items"]:
    for k in (k for k in list(dic) if k not in keysiwant):
        dic.pop(k, None)

print(data)

Output:

{'items': [{'h': 2, 'x': 0}, {'h': 7, 'x': 5}]}
Vlad Bezden
  • 83,883
  • 25
  • 248
  • 179