Issues iterating through JSON list in Python? - python

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

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.

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"]

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"])

for json_data in data['Results']:
for attribute, value in json_data.iteritems():
print attribute, value # example usage

Related

Python3 - loop through list with mulitple dictionaries

sorry I am rather a beginner when it comes to python.
I have a list like this:
"list": [
{
"id": 12345,
"name": "test"
},
{
"id": 12453,
"value": "value1",
"field": "test",
}
]
When looping through several of such lists I want it to print the "name" key from the upper dictionary but only if the condition is met that "value": "value1", is present but this is in a different dictionary.
I tried with stuff like: if 'value' in event.keys():
but I cant manage to only print this "name" key if the other condition is met. any suggestions?
Below one way of doing it, it is going through all key/value of all dictionnaries so it's probably not efficient but will adapt to several possibility.
I don't know if name can be in the list several times, the below code will keep the last occurrence if it happens.
I made it a function so that you can use it easily on several similar lists. It returns None if the criteria was not met, the value of name if it was.
def get_valid_name(dict_list, target_value):
keep_name = False
current_name = None
for d in dict_list:
for key, val in d.items():
if key == "name":
current_name = val
elif key == "value" and val == target_value:
keep_name = True
return current_name if keep_name else None
for l in [original_list]:
result = get_valid_name(l, "value1")
if result is not None:
print(result)

How to a key recursively in a dictionary and return it's value

I have a nested dictionary like below
dictionary = {"name": "Stephen", "language": "English", "address": "13 Aust road", "teacher_info": [{"name": "Alan", "language": "Italian"}]}
I want to return the languages.
Output = ["English", "Italian"]
What have I tried
output = []
for i, j in dictionary.items():
if i == "language":
output.appened(j)
For things like this recursion is your friend. The following function will find keys called language and add their value to the list.
If any of the items in the dictionary is itself a dictionary we do the same thing. We concatenate the languages found in the nested dictionary to the list at the top level.
The base case for a dictionary without any languages is an empty list.
def get_languages(dictionary):
output = []
for key, value in dictionary.items():
if key == "language":
output.appened(value)
elif isinstance(value, dict):
output += get_languages(value)
return output

Flattening a dictionary <str, list> into a comprehensive list

So I've got the following dictionary from a server request:
dict = {"first": "Mark", "last": "Zuckerberg", "alternative": ["Zuck", "Facebook guy"]}
Which I'm looking to convert into a list like this:
result = ["Mark", "Zuckerberg", "Zuck", "Facebook guy"]
I'm really trying to keep it pythonic for personal satisfaction I guess. The closest I've been to is this, which you can tell it only gives me the nested list instead of what I'm actually looking for.
values = list(dict.values())
result = [item for sublist in values for item in sublist if isinstance(sublist, list)]
Thanks for any input.
You could do:
def flatten(s):
for e in s:
if isinstance(e, (tuple, list)):
yield from flatten(e)
else:
yield e
d = {"first": "Mark", "last": "Zuckerberg", "alternative": ["Zuck", "Facebook guy"]}
result = list(flatten(d.values()))
print(result)
Output
['Mark', 'Zuckerberg', 'Zuck', 'Facebook guy']
The flatten function will deal with arbitrary nested lists.

Get parent(key) from value (an element stored in a list)

I am stuck in a problem wherein I have to find the common 'parent' of items in a list.
Here's the problem-
I have a reference file - hierarchy.json, and this file is loaded as a dictionary in my super class.
{
"DATE": ["ISO", "SYSTEM", "HTTP"],
"IP": ["IPv4", "IPv6"],
"PATH": ["UNIX", "WINDOWS"]
}
As an input, I get a list of values and I expect to get a set of elements, which belong to the same parent (referring to the hierarchy.json file) as an output. Even better, if I could get the parent name, that would be great.
input_list = ["ISO", "UNIX", "HTTP"]
result = do_something(input_list)
print('RESULT:\t', result)
>>> RESULT: set("ISO","HTTP")
Essentially, I want to make sets of the elements which belong to different "parents" in the element.
I know this can be done O(n^3) by looping through each element of the list. This is obviously not the best way to achieve the result.
Here's what I have tried -
def do_something(input_list: list, reference_dir: dict) -> list:
result_list = []
for lists in reference_dir.values():
results = []
for i in input_list:
for j in input_list:
if i != j:
if set([i,j]).issubset(set(lists)):
results.extend(set([i,j]))
result_list.append(set(results))
return result_list
input_list = ["ISO", "UNIX", "HTTP", "SYSTEM","WINDOWS"]
reference_dir = {"DATE": ["ISO", "SYSTEM", "HTTP"],"IP": ["IPv4", "IPv6"],"PATH":["UNIX", "WINDOWS"]}
result = do_something(input_list, reference_dir)
print('RESULT:\t', (result))
>>> RESULT: [{'SYSTEM', 'HTTP', 'ISO'}, set(), {'UNIX', 'WINDOWS'}]
Is there a way to optimize this/implement this in a better way?
Edited (Added) ->
ALSO,
if there's a way I could get the name of the 'parent' as the output, that would be AWESOME.
>>> RESULT: [DATE, PATH]
Thanks.
def do_something(input_list: list, reference_dir: dict) -> list:
sets_1 = {k: set() for k in reference_dir.keys()}
sets_2 = {item: sets_1[k] for k, list in reference_dir.items() for item in list}
for input in input_list:
sets_2[input].add(input)
return sets_1
reference_dir = {
"DATE": ["ISO", "SYSTEM", "HTTP"],
"IP": ["IPv4", "IPv6"],
"PATH": ["UNIX", "WINDOWS"]
}
input_list = ["ISO", "UNIX", "HTTP"]
print(do_something(input_list, reference_dir))
Prints:
{'DATE': {'HTTP', 'ISO'}, 'IP': set(), 'PATH': {'UNIX'}}
What do_something does:
sets_1 = {k: set() for k in reference_dir.keys()} This line creates a dictionary where each key is a key form reference_dir and the value is an empty set.
sets_2 = {item: sets_1[k] for k, list in reference_dir.items() for item in list} This line creates another dictionary. The keys are the elements of the lists which are the values of the reference_dir dictionary and the value for each key is the corresponding empty set created in step 1 associated with the lists owning key.
for input in input_list: sets_2[input].add(input) Each element of input_list is added to appropriate set using the dictionary created in step 2 to select the correct set.
return sets_1 This returns a dictionary whose keys are all the keys in reference_dir and whose values are now the filled in sets (some of which might be empty). The keys are the "names" of the sets you were looking for.
See Demo

Dictionary with nested list TypeError: string indices must be integers

My json response come back with this dictionary.
data = {"offset": 0, "per-page": 1, "total": 548, "language": "en",
"odds-type": "DECIMAL", "overall-staked-amount": 23428.63548,
"profit-and-loss": 4439.61471, "events": [{"id": 1042867904480016,
"name": "Gael Monfils vs Daniil Medvedev", "sport-id": 9, "sport-
url": "tennis", "sport-name": "Tennis", "start-time": "2019-02-
16T14:29:00.000Z", "finished-dead-heat": false, "markets": [{"id":
1042867905130015, "name": "Moneyline", "commission": 0, "net-win-
commission": 0, "profit-and-loss": -0.59999, "stake": 0.59999,
"selections": [{"id": "1042867905220015_BACK", "runner-id":
1042867905220015, "name": "Daniil Medvedev", "side": "BACK", "odds":
3.0, "stake": 0.59999, "commission": 0, "profit-and-loss": -0.59999,
"bets": [{"id": 1043769075060320, "offer-id": 1043764555430020,
"matched-time": "2019-02-16T16:16:18.936Z", "settled-time": "2019-
02-16T16:26:01.878Z", "in-play": true, "odds": 3.0, "stake":
0.59999, "commission": 0, "commission-rate": 2.0, "profit-and-loss":
-0.59999, "status": "PAID"}]}], "net-win-commission-rate": 0.02}]}]}
I am unable to get the attribute value for overall-staked-amount and inside the events list I cannot get name from events list. using list comprehension or a for loop.
Here's my code.
list comp
overall_staked = [d['overall-staked-amount'] for d in data]
print(overall_staked)
for loop
for d in data:
overall_staked = d['overall-staked-amount']
name = d['name']
print(overall_staked,name)
I receive an error TypeError: string indices must be integers
what am I doing wrong or need to do?
No need to iterate, just do:
overall_staked = data['overall-staked-amount']
Follow the same logic to get other data
Well, when you iterate over a dictionary, you iterate over its keys, which is a string. And, to access a string you need a int value. That's why you get this error. In your loop, d is a string and you're trying to access it's value with another string instead a int.
Did you get it?
data is a dictionary if you use for instance:
mydict = {"item_1": 3, "item_2": 5}
for item in mydict:
print(item)
it would print the dictionary keys:
item_1
item_2
That are strings, that's why if you try:
mydict = {"item_1": 3, "item_2": 5}
for item in mydict:
# item is a string here, so if you
# Python complains about string indexes must be integers.
item['overall-staked-amount']
it is exactly the same problem for comprehension.
You can get the value you want just by:
overall_staked_amount = data['overall-staked-amount']
You can iterate over keys and items by:
for key, value in data.items():
# ...

Categories

Resources