Solrac
Solrac

Reputation: 47

Looping through JSON object with a conditional

Having a bit of difficulties here with looping through this json object content. The json file is as such:

[{'archived': False,
  'cache_ttl': None,
  'collection': {'archived': False,
   'authority_level': None,
   'color': '#509EE3',
   'description': None,
   'id': 525,
   'location': '/450/',
   'name': 'eaf',
   'namespace': None,
   'personal_owner_id': None,
   'slug': 'eaf'},
  'collection_id': 525,
  'collection_position': None,
  'created_at': '2022-01-06T20:51:17.06376Z',
  'creator_id': 1,
  'database_id': 4,
  }, ... ]

And I want to loop through each dict in the list check that the collection is not empty and then for each collection if the location equals '/450/' return append that dict to a list.

My code is as follows.

content = json.loads(res.text)
for q in content:
  if q['collection']:
    for col in q['collection']:
      if col['location'] == '/450/':
        data.append(q)
  
print(data) 

Having played around with it I keep either getting ValueError: too many values to unpack (expected 2) OR TypeError: string indices must be integers Any help with my structure would be much appreciated thanks.

Disclaimer: I had previously written this as a list comprehension and it worked like a charm however that doesnt work anymore as I now need to check if the collection is empty. How I wrote it previously:

content = [ x for x in content if x['collection']['location'] == '/450/']

Upvotes: 3

Views: 4677

Answers (4)

CodeMonkey
CodeMonkey

Reputation: 23738

Don't need to iterate over the collection object since it's a dictionary and just need to check the location property.

Also, in case the "collection" or "location" properties are not present then use dict.get(key) function rather than dict[key] since the latter will raise a KeyError exception if key is not found and get() returns None value if key is not found.

content = [{'archived': False,
        'cache_ttl': None,
        'collection': {'archived': False,
                       'authority_level': None,
                       'color': '#509EE3',
                       'description': None,
                       'id': 525,
                       'location': '/450/',
                       'name': 'eaf',
                       'namespace': None,
                       'personal_owner_id': None,
                       'slug': 'eaf'},
        'collection_id': 525,
        'collection_position': None,
        'created_at': '2022-01-06T20:51:17.06376Z',
        'creator_id': 1,
        'database_id': 4,
        },
       {'foo': None}
       ]

#content = json.loads(res.text)
data = []
for q in content:
    c = q.get('collection')
    if c and c.get('location') == '/450/':
        data.append(q)
  
print(data)

Output:

[{'archived': False, 'cache_ttl': None, 'collection': { 'location': '/450/', 'name': 'eaf', 'namespace': None }, ...}]

Upvotes: 1

XBOT_ADMIN
XBOT_ADMIN

Reputation: 61

Your Code Has Way too Iterations Than needed.

The error TypeError: string indices must be integers occurs at the second conditional statement when you check col['location'] = "/450/".

That's because not all tokens in the collection object have sub-objects where you can get data with their key.

Take a look at your old code and the modified code for more in depth understanding.

# Your old json datas
content  = [{'archived': False,
  'cache_ttl': None,
  'collection': {'archived': False,
   'authority_level': None,
   'color': '#509EE3',
   'description': None,
   'id': 525,
   'location': '/450/',
   'name': 'eaf',
   'namespace': None,
   'personal_owner_id': None,
   'slug': 'eaf'},
  'collection_id': 525,
  'collection_position': None,
  'created_at': '2022-01-06T20:51:17.06376Z',
  'creator_id': 1,
  'database_id': 4,
  } ]

data = []
for q in content:
    if q['collection']:
        for col in q['collection']: 
            if col['location'] == '/450/': # The first object in collection object is [archived] which is a string, this causes the program to throw error
                data.append(q)
  
print(data) 

Here is the modified code

# Your json datas
json_datas = [{'archived': False,
  'cache_ttl': None,
  'collection': {'archived': False,
   'authority_level': None,
   'color': '#509EE3',
   'description': None,
   'id': 525,
   'location': '/450/',
   'name': 'eaf',
   'namespace': None,
   'personal_owner_id': None,
   'slug': 'eaf'},
  'collection_id': 525,
  'collection_position': None,
  'created_at': '2022-01-06T20:51:17.06376Z',
  'creator_id': 1,
  'database_id': 4,
  } ]


list_data = [] # Your list data in which appends the json data if the location is /450/

for data in json_datas: # Getting each Json data
  if len(data["collection"]): # Continue if the length of collection is not 0 [NOTE: 0 = False, 1 or more = True]
    if data['collection']['location'] == "/450/": # Check the location
      list_data.append(data) # Append if true


print(list_data)

Upvotes: 1

NixonSparrow
NixonSparrow

Reputation: 6378

That should work for you:

for q in content:
    if q['collection']['location'] == '/450/':
        data.append(q)
  
print(data)

If you go with for loop with for col in q['collection'], you just iterate over keys inside q['collection'], so cols = ['archived', 'authority_level', ...].

Upvotes: 3

Kraigolas
Kraigolas

Reputation: 5560

From your previous list comprehension, "location" is a key in q["collection"]. When you write

for col in q["collection"]

You are iterating over the keys in q["collection"]. One of these keys is "location". Your for loop seems to iterate more than necessary:

if q['collection'] and "location" in q["collection"] and q["collection"]["location"]  == "/450/":
    data.append(q)

Upvotes: 1

Related Questions