Access a dictionary key inside a dictionary key [closed] - python

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I'm trying to make a program that gets a country name, goes to restcountries.com, gets the country's current population number, does the same thing another time, and tells if the population got bigger/smaller/same. I am a beginner at python and coding, so existing answers to similar questions were not so useful to me since they seem different than my problem. I have managed to make the code get the JSON from the site, keep it, and tell me the population number and it worked (I tested it with "Israel". But when I gave it to my pal, he wrote "Russia" and it failed. After a short investigation, I discovered restcountries.com calls Russia by the name "Russian Federation" and has a separate JSON dictionary key for common names called "common:". But I can't get to it and extract it by code. Here is the JSON from this URL: https://restcountries.com/v3/name/russia?fields=name,population
[{"name":{"common":"Russia","official":"Russian Federation","nativeName":{"rus":{"official":"Российская Федерация","common":"Россия"}}},"population":144104080}]
Here is my current code:
import bs4
import urllib.request
import json
country_name = input("Choose country: ")
# Getting updated list and saving it as "json_data"
link = 'https://restcountries.com/v3/name/' + country_name + '?fields=name,population'
webpage = str(urllib.request.urlopen(link).read())
soup = bs4.BeautifulSoup(webpage, "html.parser")
json_data = soup.get_text()
# Cleans json_data from all the bullshit
clean_json = json_data[:-1][2:].replace('\\', '.') \
.replace('.xc3.x85', 'A').replace('.xc3.xa7', 'c').replace('.xc3.xa9', 'e')
# Convert clean_json to a dictionary
loaded_json = json.loads(clean_json)
# Country search function
def search(name):
for p in loaded_json:
if p['name'] == name:
return p['population']
# Choose Country, save data.
country_population = search(country_name)
datafile = open('G:\HackerU\Python\Challenges\Population\dataname.txt','w')
def save(done):
datafile = open('G:\HackerU\Python\Challenges\Population\dataname.txt','w')
datafile.write(country_population)
datafile.close()
return True
saved_population_number = datafile.read()
if saved_population_number > country_population:
print("Population number has been decreased.")
elif saved_population_number < country_population:
print("Population number has risen.")
elif saved_population_number == country_population:
print("Population number stayed the same.")
else:
print("Unknown Error.")
How do I make my code recognize a country only by its "common" name?

It seems that there is a lot of unnecessary code here:
First of all, an API returns a JSON, therefore I don't see why you need to use bs4. You can load the JSON into a dict using json.loads.
Secondly, you don't want a string representation of the bytes object - but to decode the bytes. Therefore you can use urllib.request.urlopen(req).read().decode().
Therefore I would do something like this:
import json
import urllib.request
country_name = input("Choose country: ")
req = 'https://restcountries.com/v3/name/' + country_name + '?fields=name,population'
response = json.loads(urllib.request.urlopen(req).read().decode())[0]
Now you have the JSON response in a dictionary, and accessing response['population] gets you the country's population.
In addition, I would recommend learning about context managers and using them. For example, I would change the save function to (also, why does it return True?):
def save(country_population):
with open('G:\HackerU\Python\Challenges\Population\dataname.txt','w') as datafile:
datafile.write(country_population)
Good luck in the course, Python is a great language to start coding with.

Your issue has to do with how the json data is formatted. Replace if p['name'] == name: by if p['name']['common'] == name:

Related

Creating functions to read file in python [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 months ago.
Improve this question
This a sample txt file called "price_file.txt":
Apple,$2.55
Banana,$5.79
Carrot,$8.19
Dragon Fruit,$8.24
Eggs,$1.44
Hamburger Buns,$1.89
Ice Pops,$4.42
This is a function to allow the user to read the file:
def addpricefile (price_file):
# input: price file txt
# output: item mapped to its price in a dictionary
global item_to_price
for next_line in price_file:
item,price = next_line.strip().split(',')
item_to_price[item]= float(price[1:]) #map item to price
return item_to_price
p = input ("Enter price file: ")
price_file2 = open(p, "r")
price_file = price_file2.readlines()
for next_line in price_file:
addpricefile(price_file2)
print(item_to_price)
price_file2.close()
However, I get an empty dictionary as the output. How do I fix this?
Try this code, I was a bit confused by what you had there but you can simplify the operation a bit. This will achieve the same result. I hope this helps you solve your problem.
def openAndSeperate(filename):
with open(filename,'r') as file:
priceList = {}
for i in file:
i = i.strip('\n').split(',')
priceList[i[0]] = float(str(i[1])[1:])
return priceList
def main():
filename = 'price_file.txt'#input('Enter File Name: \n')
priceList = openAndSeperate(filename)
print(priceList)
if __name__ == '__main__':
main()

Error is being shown when I run the code and I am unable to figure out the second question

import pickle
med = {}
medfile = open("Medicines.dat","wb")
while True:
name = input("Enter the name: ")
company = input("Enter the company: ")
chemical = input("Enter the chemical: ")
price = input("Enter the price: ")
med['name'] = name
med['company'] = company
med['chemical'] = chemical
med['price'] = price
pickle.dump(med,medfile)
ans = input("Wouldyou like to add more(y/n) ")
if ans == "y":
continue
elif ans == "n":
break
medfile = open("Medicines.dat","r+")
print(pickle.load(medfile))
medfile.close()
The question is as follows:
A binary file "Medicines.dat has structure [Name, Company, Chemical, Price] a) Write a user defined function add_data() to input the data for a record and store in the file b) Write a function search() which accepts a company name and displays the details of all the Medicines by that company
There are a few problems here:
1st Opening the file correctly
medfile = open("Medicines.dat","r+")
You mean rb. The difference is explained here, but pickle parsing requires the file to be in "binary" mode, hence the "b".
2nd Closing the file correctly
You should close the file before re-opening it for writing, as a matter of best practce. (medfile.close()). Even better, python will take care of when the file gets closed if you use the "with" syntax to create a context
3rd Having the right values
While the code should now run, I doubt it will do what you want. Your query asks "Wouldyou [sic] like to add more(y/n)", but it does not look to me like it is adding more values, since you use the same "med" dictionary over and over. Consider how the "new" fields would ever be distinguishable from the "old" ones, based on their key

Python Dictionaries stuck

hope you are having a nice day, so I need to write a code that takes an input, which is going to be a key in an already existing dictionary, and prints the value as a str as described in the pic. I am stuck rn, I am a beginner and tried everything I see on the web related, appriciate any help, thank you.
[and these are the codes I tried][1]
def read_dataset(filename):
lines = open(filename).readlines()
lines_splitted = [line.strip().split(',') for line in lines]
return {lst[0]: lst[1:] for lst in lines_splitted}
movie_dict = read_dataset('dataset.txt')
# DO_NOT_EDIT_ANYTHING_ABOVE_THIS_LINE
hey = input('Enter a movie name: ')
actors = movie_dict[hey]
# DO_NOT_EDIT_ANYTHING_BELOW_THIS_LINE
print(','.join(sorted(actors)))
So this is my assignment
If you begin, try using pandas to make a dataframe of your base. It will be easier to use, and you should reuse it in a lot of cases.
Here an example of what you could do. If you don't understand a point, do not hesitate to ask me:
# import the package
import pandas as pd
# build the dataframe for the example
film = pd.DataFrame({'film':['Goldorak','Mickey Mouse'],'actors':[['Actarus','Alkor'],['Mickey, Minnie, Pluto, Goofy']]})
# the input
query = input('Enter the film')
# the 'search' engine
if len(film[film.film==query].actors)>0:
print(film[film.film==query].actors)
else:
print('not found in base')
EDIT with Dictionary :
FILM = {'Forest Gump':['Tom Hanks', 'Gary Sinise']}
query = None
query = input('Enter the film')
try:
print(FILM.get(query))
except:
pass

Finding a specific record in a csv file

I'm making a project for school where users are quizzed on subjects and their results are saved into a report (CSV file called 'reportForFergusTwo') for the 'customer' (Fergus). The report shows the average score a certain quiz, the high score, and the username of the person who achieved it. And then, I'm meant to display the user's details but the user's details are saved in a different CSV file ('details').
So far I've made a function that finds the highest score and username of the person who achieved it in the CSV 'reportForFergusTwo'. I now need to work on a function that searches through another CSV file ('details').
def findHighScoreUser():
print(user)
with open ('details.csv', 'r') as stalking:
stalkingReader=csv.reader(stalking)
valid4=False
for row in stalkingReader:
if user in row:
valid4=True
print("Here are the details for user {}... ".format(user))
splitter=row.split(',')
name=splitter[0]
age=splitter[1]
year=splitter[2]
print("Name: {}".format(name))
print("Age: {}".format(age))
print("Year Group: {}".format(year))
postReport()
if valid4==False:
print("Sorry Fergus, this user doesn't seem to be in our records.")
'user' is a variable from my previous function, where I found the username of the person with the highest score. It holds the username. I made it global and printed it at the start of this function, and that's working, making me think this is an issue I've made in reading the CSV.
Here is the details CSV:
Name,Age,Year Group,Username,Password
Erin Jones,15,11,Eri15,Password
Lucas Jones,16,11,Luc16,Password2
Michael Jordan,11,7,Mic11,GetSomeHelp
La Roux,14,9,La 14,Bulletproof
And here is the reportForFergusTwo CSV:
Subject,Difficulty,Score,Username
language,easy,10,Luc16
chemistry,easy,10,Luc16
maths,easy,9,Luc16
chemistry,easy,5,Eri15
chemistry,easy,6,Mic11
chemistry,easy,0,Eri15
I'm still fairly new to code, so please excuse me if the answer is obvious.
If your user is no longer in scope you can provide it to your function like this:
def functionThatFindsHighestScoreUser():
# do stuff
return maxScoreUser
def findHighScoreUser(user):
print(user)
# the rest of your existing code
# get the user
maxScoreUser = functionThatFindsHighestScoreUser()
# find it and print details
findHighScoreUser(maxScoreUser)
There is almost always a way around global variables by using parameters in the function - don't use them, provide each function exactly with what it needs.
As for the csv-issues: csv module does the splitting for you as Tomalak mentioned. You can consume the reader line wise and get a list of all fields:
import csv
def checkUsers(name):
with open("users.csv",encoding="utf8",newline='\n') as u:
reader = csv.DictReader(u, delimiter=',', quotechar='|' )
found = False
for row in reader:
if row["Name"] == name:
print("Here are the details for user {}... ".format(row["Name"]))
print("Name: {}".format( row["Name"]))
print("Age: {}".format( row["Age"]))
print("Year Group: {}".format( row["Year Group"]))
found = True
break # leave for loop
if not found:
print("Not in users")
checkUsers("Michael Jordan")
checkUsers("Chris Cringle")
Output:
OrderedDict([('Name', 'Michael Jordan'), ('Age', '11'),
('Year Group', '7'), ('Username', 'Mic11'), ('Password', 'GetSomeHelp')])
Not in users
Try this?:
import pandas
#read csv data
stalking = pandas.read_csv('details.csv')
#Select all records from the stalking csv where Username equals the user you are looking for
user_details = stalking[stalking['Username']==user]
#Print values for each column from subset of data which only contains records where username == user
print('Name: {}'.format(user_details['Name']))
print('Age: {}'.format(user_details['Age']))
print('Year Group: {}'.format(user_details['Year Group']))
edit: FYI if there are multiple rows with the same username this will print all the names, ages and year groups associated with that username.
pandas makes accessing and working with csvs really easily. Once you've done var = pandas.read_csv('somefile.csv') you can access all the values in a given column using var['col1']. Subsetting can be done by doing var[var['col1'] == 'something'], which reads as 'Select records from dataset var where the values of col1 are 'something'.
The pandas docs can be found here: http://pandas.pydata.org/pandas-docs/stable/
Dictreader might also be a good way to go if pandas seems a bit too complex for what you're tyring to do.

How can I optimize my simple code (python)? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I'm taking an intro programming class and am working ahead on some assignments that aren't due for a few weeks. This one asks me to take three text files - names, titles, and descriptions - and use them to randomly generate "fantasy character" names. My code runs and does what I want it to, but I feel like it's cluttered and could be cleaned up quite a bit. Keep in mind that this is an INTRO course and in class have just covered basic boolean logic, loops, arrays, etc.; not classes, object-oriented, or any advanced stuff (I'm trying to learn some of this on my own).
import random
def main():
for i in range(10):
# Load names, titles, descriptions into arrays
names = loadFile('names.txt')
title = loadFile('titles.txt')
descriptor = loadFile('descriptors.txt')
# Generate random number based on list length
nameListLength = len(names)
titleListLength = len(title)
descListLength = len(descriptor)
firstNameIndex = random.randrange(nameListLength)
lastNameIndex = random.randrange(nameListLength)
randTitleIndex = random.randrange(titleListLength)
randDescriptor = random.randrange(descListLength)
# Choose random list entry
firstName = names[firstNameIndex]
lastName = names[lastNameIndex]
title2 = title[randTitleIndex]
description = descriptor[randDescriptor]
nameList = [title2, firstName, lastName, description]
dumpFile(nameList)
print(title2, firstName, lastName, 'the', description)
print()
print('These names have been written to \"CharacterNames.txt\".')
def dumpFile(nameList):
title = str(nameList[0])
firstName = str(nameList[1])
lastName = str(nameList[2])
descriptor = str(nameList[3])
outfile = open('CharacterNames.txt', 'a')
outfile.write(title + ' ' + firstName + ' ' + lastName + ' ' +
'the' + ' ' + descriptor + '\n')
outfile.write('\n')
outfile.close()
def loadFile(nameFile):
nameList = open(nameFile, 'r')
nameArray = []
for line in nameList:
name = line
name = name.rstrip('\n')
nameArray.append(name)
nameList.close()
return nameArray
main()
I see value in having others look at your code and rewrite it as they would do it. I kind of ignored your restriction on "any advanced stuff," although I don't think any of it will be too complicated for you to intuit. Here's my rewrite:
import random
def generatePerson(names=loadFile('names.txt'),
titles=loadFile('titles.txt'),
descriptons=loadFile('descriptors.txt')):
firstName = random.choice(names)
lastName = random.choice(names)
title = random.choice(titles)
description = random.choice(descriptons)
return '{} {} {} the {}'.format(title, firstName, lastName, description)
def main():
people = [generatePerson() for _ in range(10)]
dumpFile('\n\n'.join(people))
print('\n'.join(people))
print('\nThese names have been written to "CharacterNames.txt".')
def dumpFile(data, filename='CharacterNames.txt'):
with open(filename, 'a') as outfile:
outfile.write(data)
def loadFile(nameFile):
with open(nameFile, 'r') as nameList:
return nameList.read().splitlines()
if __name__ == '__main__':
main()
It still resembles your code in many ways, however, most of it has been rewritten. Now for details on some of the more drastic changes.
I moved the code related to picking random strings from the three lists into its own function generatePerson. This makes the easier to maintain in case the method of generating a random person or something else changes in the future.
I greatly simplified the logic of picking the random strings by using random.choice.
I used a trick that uses default arguments in generatePerson to avoid reading from the three files each time a random name is created. The only part of this trick that you should know for now is that the values of default arguments are created only once in Python.
Instead of passing a list into dumpFile, I opted to pass a string, which I can then immediately write to the file. This makes more sense because I had generatePerson return the formatted string for that person rather than [title, firstName, lastName, description].
This is mostly just my preference, but I don't really like for-loops, so in main I used a list comprehension to create a list of 10 random names. From there, I used str.join to create a single string with all ten names that is suitable to be passed to dumpFile and print.
I believe that is (nearly) all of the changes I made. If I missed something or if you need further clarification on anything I mentioned either comment on my answer or just ask a new question.
Move file operations before the 'for' loop - there is no need to re-read the files 10 times. That should make the application run much faster.

Categories