how to get specific value in python dictionary? - python

I call an api via python and return this code as response:
{
"cast": [
{
"character": "Power",
"name": "George"
},
{
"character": "Max",
"job": "Sound",
"name": "Jash"
},
{
"character": "Miranda North",
"job": "Writer",
"name": "Rebecca"
}
]
}
I am trying to get the value of Rebecca because i need to get the Writer.
So i wrote:
for person in cast # cast is the variable keeps whole code above NOT inside the dict:
if person["job"] == "Writer":
writer = person["name"]
but it gives me:
KeyError at search/15
u'job'
how can i get the value?
FULL CODE:
writer = ""
for person in api['cast']:
if person.get('job') == 'Writer':
writer = person.get('name')
return render(request, 'home.html', {
'writer': writer
})
home.html:
<p>{{writer}}</p>

That's because not all elements in the list have the job key.
Change to:
for person in cast #whole code above:
if person.get('job') == 'Writer':
writer = person.get('name')

One liner to find one writer.
writer = next((person for person in api['cast'] if person.get('job') == 'Writer'), None)
One liner to find all writers.
writers = [person for person in api['cast'] if person.get('job') == 'Writer']

Syntax for dictionary get() method:
dict.get(key, default=None)
Parameters
key: This is the Key to be searched in the dictionary.
default: This is the Value to be returned in case key does not exist.
You need to specify the default value for get in case the key doesn't exist.
>>> for person in api['cast']:
... if person.get('job', '') == 'Writer':
... writer = person.get('name')

person.get(u"job") == "Writer"

for person in cast["cast"]:
# cast is the variable keeps whole code above NOT inside the dict
if person["job"] == "Writer":
writer = person["name"]
try this
cast["cast"] == Value of Key "cast" , which in turn is list of Dicts
and for looping through each Dictionary as person

Related

python dictionary update without overwriting

I am learning python, and I have two json files. The data structure in these two json files are different structures.
I start by importing both of the json files. I want to choose a course from the courses dict, and then add it to a specific education in the educations dict.
What I want to solve is via user input choose a key from the first dict, and then within a while loop, so I can add choose a key from the second dict to be added to the dict chosen from the first dict.
I am able to add the dict from the second dict to the one first as a sub dict as I want to, but with the update method it overwrites all previous values.
I have used the dict.update() method so not to overwrite previous values. I then want to write back the updated dict back to the first json file.
My code works partially, I am able to add a course to a educations, but it overwrites all previous courses I chose to add to a specific education.
This is the content of the first json file:
{
"itsak22": {
"edcuationId": "itsak22",
"edcuation_name": "cybersecurityspecialist"
},
"feu22": {
"edcuationId": "feu22",
"edcuation_name": "frontendutvecklare"
}
}
This is the content of the second json file:
{
"sql": {
"courseId": "itsql",
"course_name": "sql",
"credits": 35
},
"python": {
"courseId": "itpyt",
"course_name": "python",
"credits": 30
},
"agile": {
"courseId": "itagl",
"course_name": "agile",
"credits": 20
}
}
And this is my python code:
import json
# Load the first JSON file of dictionaries
with open('edcuations1.json') as f:
first_dicts = json.load(f)
# Load the second JSON file of dictionaries
with open('courses1.json') as f:
second_dicts = json.load(f)
# Print the keys from both the first and second JSON files
print("All educations:", first_dicts.keys())
print("All courses:", second_dicts.keys())
# Ask for input on which dictionary to add to which
first_key = input("Which education would you like to choose to add courses to? (Enter 'q' to quit): ")
while True:
second_key = input("Which course would you like to add to education? (Enter 'q' to quit)")
if second_key == 'q':
break
# Create a sub-dictionary named "courses" in the specific dictionary of the first file
if "courses" not in first_dicts[first_key]:
first_dicts[first_key]["courses"] = {}
first_dicts[first_key]["courses"].update(second_dicts[second_key])
#first_dicts = {**first_dicts, **second_dicts}
#first_dicts.update({'courses': second_dicts})
# Update the first JSON file with the new dictionaries
with open('edcuations1.json', 'w') as f:
json.dump(first_dicts, f, indent=4)
Here is my approach:
import json
# Load the first JSON file of dictionaries
with open("educations1.json") as f:
educations = json.load(f)
# Load the second JSON file of dictionaries
with open("courses1.json") as f:
courses = json.load(f)
# Print the keys from both the first and second JSON files
print("All educations:", educations.keys())
print("All courses:", courses.keys())
# Ask for input on which dictionary to add to which
education_key = input(
"Which education would you like to choose to add courses to? (Enter 'q' to quit): "
)
education_courses = educations[education_key].setdefault("courses", {})
while True:
course_key = input(
"Which course would you like to add to education? (Enter 'q' to quit): "
)
if course_key == "q":
break
education_courses[course_key] = courses[course_key]
# Update the first JSON file with the new dictionaries
with open("educations1.json", "w") as stream:
json.dump(educations, stream, indent=4)
A few notes
I fixed the typos: edcuations1.json -> educations1.json
Instead of generic names such as first_dicts, first_keys, ... I use more descriptive names
How it works
The heart of my solution is on this line:
education_courses = educations[education_key].setdefault("courses", {})
Which is the equivalent of:
if "courses" not in educations[education_key]:
educations[education_key]["courses"] = {}
education_courses = educations[education_key]["courses"]
The setdefault method basically assign a value (an empty dictionary in this case) to a dictionary if the key ("courses" in this case) is absent.
I'm not entirely sure how your desired result should look like but I think your dictionary courses should be a list and not a dictionary.
Then you can do
if "courses" not in first_dicts[first_key]:
first_dicts[first_key]["courses"] = []
first_dicts[first_key]["courses"].append (second_dicts[second_key])
And your result looks like this if you add all courses to itsak22
{
"itsak22": {
"edcuationId": "itsak22",
"edcuation_name": "cybersecurityspecialist",
"courses": [
{
"courseId": "itsql",
"course_name": "sql",
"credits": 35
},
{
"courseId": "itpyt",
"course_name": "python",
"credits": 30
},
{
"courseId": "itagl",
"course_name": "agile",
"credits": 20
}
]
},
"feu22": {
"edcuationId": "feu22",
"edcuation_name": "frontendutvecklare"
}
}

Editing Json Program

My code gets a json path file, open/parses it and prints out desired values with help of a csv mapping file set up (knows what key words to look for and what name to print values out as).
Some json files, however, have multiple values for example, a json file with key "Affiliate" will have more key/value pairs inside of it instead of just having a value.
How can I parse within a key like this one and print out the 'true' value vs the 'false' ones? Currently my code would print out the entire array of key value pairs within that target key.
Example json:
"Affiliate": [
{
"ov": true,
"value": "United States",
"lookupCode": "US"
},
{
"ov": false,
"value": "France",
"lookupCode": "FR"
}
]
My code:
import json
import csv
output_dict = {}
#maps csv and json information
def findValue(json_obj, target_key, output_key):
for key in json_obj:
if isinstance(json_obj[key], dict):
findValue(json_obj[key], target_key, output_key)
else:
if target_key == key:
output_dict[output_key] = json_obj[key]
#Opens and parses json file
file = open('source_data.json', 'r')
json_read = file.read()
obj = json.loads(json_read)
#Opens and parses csv file (mapping)
with open('inputoutput.csv') as csvfile:
fr = csv.reader(csvfile)
for row in fr:
findValue(obj, row[0], row[1])
#creates/writes into json file
with open("output.json", "w") as out:
json.dump(output_dict, out, indent=4)
So you'll need to change the way that the mapping CSV is structured, as you'll need variables to determine which criteria to meet, and which value to return when the criteria is met...
Please note that with the logic implemented below, if there are 2 list items in Affiliate that both have the key ov set to true that only the last one will be added (dict keys are unique). You could put a return where I commented in the code, but then it would only use the first one of course.
I've restructured the CSV as below:
inputoutput.csv
Affiliate,Cntr,ov,true,value
Sample1,Output1,,,
Sample2,Output2,criteria2,true,returnvalue
The JSON I used as the source data is this one:
source_data.json
{
"Affiliate": [
{
"ov": true,
"value": "United States",
"lookupCode": "US"
},
{
"ov": false,
"value": "France",
"lookupCode": "FR"
}
],
"Sample1": "im a value",
"Sample2": [
{
"criteria2": false,
"returnvalue": "i am not a return value"
},
{
"criteria2": true,
"returnvalue": "i am a return value"
}
]
}
The actual code is below, note that I commented a bit on my choices.
main.py
import json
import csv
output_dict = {}
def str2bool(input: str) -> bool:
"""simple check to see if a str is a bool"""
# shamelessly stolen from:
# https://stackoverflow.com/a/715468/9267296
return input.lower() in ("yes", "true", "t", "1")
def findValue(
json_obj,
target_key,
output_key,
criteria_key=None,
criteria_value=False,
return_key="",
):
"""maps csv and json information"""
# ^^ use PEP standard for docstrings:
# https://www.python.org/dev/peps/pep-0257/#id16
# you need to global the output_dict to avoid weirdness
# see https://www.w3schools.com/python/gloss_python_global_scope.asp
global output_dict
for key in json_obj:
if isinstance(json_obj[key], dict):
findValue(json_obj[key], target_key, output_key)
# in this case I advise to use "elif" instead of the "else: if..."
elif target_key == key:
# so this is the actual logic change.
if isinstance(json_obj[key], list):
for item in json_obj[key]:
if (
criteria_key != None
and criteria_key in item
and item[criteria_key] == criteria_value
):
output_dict[output_key] = item[return_key]
# here you could put a return
else:
# this part doesn't change
output_dict[output_key] = json_obj[key]
# since we found the key and added in the output_dict
# you can return here to slightly speed up the total
# execution time
return
# Opens and parses json file
with open("source_data.json") as sourcefile:
json_obj = json.load(sourcefile)
# Opens and parses csv file (mapping)
with open("inputoutput.csv") as csvfile:
fr = csv.reader(csvfile)
for row in fr:
# this check is to determine if you need to add criteria
# row[2] would be the key to check
# row[3] would be the value that the key need to have
# row[4] would be the key for which to return the value
if row[2] != "":
findValue(json_obj, row[0], row[1], row[2], str2bool(row[3]), row[4])
else:
findValue(json_obj, row[0], row[1])
# Creates/writes into json file
with open("output.json", "w") as out:
json.dump(output_dict, out, indent=4)
running the above code with the input files I provided, results in the following file:
output.json
{
"Cntr": "United States",
"Output1": "im a value",
"Output2": "i am a return value"
}
I know there are ways to optimize this, but I wanted to keep it close to the original. You might need to play with the exact way you add stuff to output_dict to get the exact output JSON you want...

How get variable (which does not exist in a message) from JSON message?

I have a JSON message. And I want to return values that stand for "Brand", but in this message it does not exist, so this value needs to be replaced by another. How can I do that? I tried with try/except, however the values are not replaced.
import json
message = [
{
"ID": 48,
"Type": "Update",
"UpdateType": "Quote",
"Key": {
"Service": "Online",
"Name": "Audi"
},
"Fields": {
"Buyers": 1000,
"Sellers": 500,
"Year": 2020
}
}
]
data=json.loads(message)
#data[0]['ID'] this works as there is ID
try:
data[0]['Brand']
except :
9999 #no output seen
From your question:
I want to return values that stand for "Brand", but in this message, the "Brand does not exist, so this value is needed to be replaced by another. How can I do it?
So you want to retrieve entry from a list, then get item from the entry for example Brand.
and if there is no such Brand in the entry then add Brand item to the entry.
Am I right?
if so, your code may changed to:
import json
message = '[{"ID":48,"Type":"Update","UpdateType":"Quote","Key": {"Service":"Online","Name":"Audi"},"Fields":{"Buyers":1000,"Sellers":500,"Year":2020}}]'
data=json.loads(message) # here message should be a json-string
#data[0]['ID'] this works as there is ID
try:
data[0]['Brand']
except KeyError:
# 9999 #no output seen
data[0]['Brand'] = NewItem # the item you want to replace
You need to itinerante thru the list and check in one of then contains the key. This being done on a python objects and not on a raw json string
message = [{"ID":48,"Type":"Update","UpdateType":"Quote","Key":{"Service":"Online","Name":"Audi"},"Fields":{"Buyers":1000,"Sellers":500,"Year":2020}}]
def item_exists_ofd(dic_list, item):
for dic in dic_list:
if item in dic:
return dic
return None
if __name__ == '__main__':
match = item_exists_ofd(message, 'Brand')
if match:
print(match['Brand'])
else:
print('Brand, not found')
match = item_exists_ofd(message, 'ID')
if match:
print(match['ID'])
else:
print('ID, not found')

How do I extract a list item from nested json in Python?

I have a json object and I'm trying to extract a couple of values from a nested list. Then print them in markup. I'm getting and error - AttributeError: 'list' object has no attribute 'get'
I understand that it's a list and I can't preform a get. I've been searching for the proper method for a few hours now and I'm running out of steam. I'm able to get the Event, but not Value1 and Value2.
This is the json object
{
"resource": {
"data": {
"event": "qwertyuiop",
"eventVersion": "1.05",
"parameters": {
"name": "sometext",
"othername": [
""
],
"thing": {
"something": {
"blah": "whatever"
},
"abc": "123",
"def": {
"xzy": "value"
}
},
"something": [
"else"
]
},
"whatineed": [{
"value1": "text.i.need",
"value2": "text.i.need.also"
}]
}
}
}
And this is my function
def parse_json(json_data: dict) -> Info:
some_data = json_data.get('resource', {})
specific_data = some_data.get('data', {})
whatineed_data = specific_data.get('whatineed', {})
formatted_json = json.dumps(json_data, indent=2)
description = f'''
h3. Details
*Event:* {some_data.get('event')}
*Value1:* {whatineed_data('value1')}
*Value2:* {whatineed_data('value2')}
'''
From the data structure, whatineed is a list with a single item, which in turn is a dictionary. So, one way to access it would be:
whatineed_list = specific_data.get('whatineed', [])
whatineed_dict = whatineed_list[0]
At this point you can do:
value1 = whatineed_dict.get('value1')
value2 = whatineed_dict.get('value2')
You can change your function to the following:
def parse_json(json_data: dict) -> Info:
some_data = json_data.get('resource')
specific_data = some_data.get('data', {})
whatineed_data = specific_data.get('whatineed', {})
formatted_json = json.dumps(json_data, indent=2)
description = '''
h3. Details
*Event:* {}
*Value1:* {}
*Value2:* {}
'''.format(some_data.get('data').get('event'),whatineed_data[0]['value1'], whatineed_data[0]['value2'])
Since whatineed_data is a list, you need to index the element first
Python handles json as strings unless they are coming directly from a file. This could be the source for some of your problems. Also this article might help.
Assuming that "whatineed" attribute is really a list, and it's elements are dicts, you can't call whatineed.get asking for Value1 or Value2 as if they are attributes, because it is a list and it don't have attributes.
So, you have two options:
If whatineed list has a single element ever, you can access this element directly and than access the element attributes:
element = whatineed[0]
v1 = element.get('value1', {})
v2 = element.get('value2', {})
Or, if whatineed list can have more items, so, you will need to iterate over this list and access those elements:
for element in whatineed:
v1 = element.get('value1', {})
v2 = element.get('value2', {})
## Do something with values

List Indices in json in Python

I've got a json file that I've pulled from a web service and am trying to parse it. I see that this question has been asked a whole bunch, and I've read whatever I could find, but the json data in each example appears to be very simplistic in nature. Likewise, the json example data in the python docs is very simple and does not reflect what I'm trying to work with. Here is what the json looks like:
{"RecordResponse": {
"Id": blah
"Status": {
"state": "complete",
"datetime": "2016-01-01 01:00"
},
"Results": {
"resultNumber": "500",
"Summary": [
{
"Type": "blah",
"Size": "10000000000",
"OtherStuff": {
"valueOne": "first",
"valueTwo": "second"
},
"fieldIWant": "value i want is here"
The code block in question is:
jsonFile = r'C:\Temp\results.json'
with open(jsonFile, 'w') as dataFile:
json_obj = json.load(dataFile)
for i in json_obj["Summary"]:
print(i["fieldIWant"])
Not only am I not getting into the field I want, but I'm also getting a key error on trying to suss out "Summary".
I don't know how the indices work within the array; once I even get into the "Summary" field, do I have to issue an index manually to return the value from the field I need?
The example you posted is not valid JSON (no commas after object fields), so it's hard to dig in much. If it's straight from the web service, something's messed up. If you did fix it with proper commas, the "Summary" key is within the "Results" object, so you'd need to change your loop to
with open(jsonFile, 'w') as dataFile:
json_obj = json.load(dataFile)
for i in json_obj["Results"]["Summary"]:
print(i["fieldIWant"])
If you don't know the structure at all, you could look through the resulting object recursively:
def findfieldsiwant(obj, keyname="Summary", fieldname="fieldIWant"):
try:
for key,val in obj.items():
if key == keyname:
return [ d[fieldname] for d in val ]
else:
sub = findfieldsiwant(val)
if sub:
return sub
except AttributeError: #obj is not a dict
pass
#keyname not found
return None

Categories