17

I have a file with JSON data in it, like so:

{
    "Results": [
            {"Id": "001",
            "Name": "Bob",
            "Items": {
                "Cars": "1",
                "Books": "3",
                "Phones": "1"}
            },

            {"Id": "002",
            "Name": "Tom",
            "Items": {
                "Cars": "1",
                "Books": "3",
                "Phones": "1"}
            },

            {"Id": "003",
            "Name": "Sally",
            "Items": {
                "Cars": "1",
                "Books": "3",
                "Phones": "1"}
            }]
}

I can not figure out how to properly loop through the JSON. I would like to loop through the data and get a Name with the Cars for each member in the dataset. How can I accomplish this?

import json

with open('data.json') as data_file:
    data = json.load(data_file)

print data["Results"][0]["Name"] # Gives me a name for the first entry
print data["Results"][0]["Items"]["Cars"] # Gives me the number of cars for the first entry

I have tried looping through them with:

for i in data["Results"]:
print data["Results"][i]["Name"]    

But recieve an error: TypeError: list indices must be integers, not dict

Bajan
  • 634
  • 3
  • 12
  • 30

4 Answers4

31

You are assuming that i is an index, but it is a dictionary, use:

for item in data["Results"]:
    print item["Name"]    

Quote from the for Statements:

The for statement in Python differs a bit from what you may be used to in C or Pascal. Rather than always iterating over an arithmetic progression of numbers (like in Pascal), or giving the user the ability to define both the iteration step and halting condition (as C), Python’s for statement iterates over the items of any sequence (a list or a string), in the order that they appear in the sequence.

alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
  • That makes sense now, thanks for your quick reply!! I am still unsure how I would loop through the sub-object for each one though? – Bajan Jan 22 '16 at 16:47
  • 2
    @Bajan sure, assuming you mean the `Items` dictionary: `for key, value in item["Items"].iteritems():`. Please see the related topics: https://docs.python.org/2/tutorial/datastructures.html#dictionaries, http://stackoverflow.com/questions/3294889/iterating-over-dictionaries-using-for-loops-in-python. – alecxe Jan 22 '16 at 16:48
  • 1
    You are quick! I got it done by using this: `for item in data["Results"]: print item["Items"]["Cars"]` Which would be the recommended method? – Bajan Jan 22 '16 at 16:49
7

you are iterating through the dictionary not indexes so you should either use.

for item in data["Results"]:
    print item["Name"]    

or

for i in range(len(data["Results"])):
    print data["Results"][i]["Name"]
geo_pythoncl
  • 927
  • 1
  • 7
  • 13
5

The confusion is in how dictionaries and lists are used in iteration. A dictionary will iterate over it's keys (which you use as indices to get corresponding values)

x = {"a":3,  "b":4,  "c":5}
for key in x:   #same thing as using x.keys()
   print(key,x[key]) 

for value in x.values():
    print(value)      #this is better if the keys are irrelevant     

for key,value in x.items(): #this gives you both
    print(key,value)

but the default behaviour of iterating over a list will give you the elements instead of the indices:

y = [1,2,3,4]
for i in range(len(y)):  #iterate over the indices
    print(i,y[i])

for item in y:
    print(item)  #doesn't keep track of indices

for i,item in enumerate(y): #this gives you both
    print(i,item)

If you want to generalize your program to handle both types the same way you could use one of these functions:

def indices(obj):
    if isinstance(obj,dict):
        return obj.keys()
    elif isinstance(obj,list):
        return range(len(obj))
    else:
        raise TypeError("expected dict or list, got %r"%type(obj))

def values(obj):
    if isinstance(obj,dict):
        return obj.values()
    elif isinstance(obj,list):
        return obj
    else:
        raise TypeError("expected dict or list, got %r"%type(obj))

def enum(obj):
    if isinstance(obj,dict):
        return obj.items()
    elif isinstance(obj,list):
        return enumerate(obj)
    else:
        raise TypeError("expected dict or list, got %r"%type(obj))

this way if you, for example, later changed the json to store the results in a dict using the id as keys the program would still iterate through it the same way:

#data = <LOAD JSON>
for item in values(data["Results"]):
    print(item["name"])

#or
for i in indices(data["Results"]):
    print(data["Results"][i]["name"])
Tadhg McDonald-Jensen
  • 20,699
  • 5
  • 35
  • 59
1
for json_data in data['Results']:
    for attribute, value in json_data.iteritems():
        print attribute, value # example usage