Access nested list within a dictionary - python

So I'm working on a lab studying multilayer dictionaries, the goal is to receive an input of a string including a country and three cities located in this country, i.e.
string = "Spain Madrid Barcelona Valencia", then ask for an input (city = "Madrid"). If the city has been previously input, the output should be Madrid is located in Spain, otherwise the output should be No data on input city.
I've come up with the following:
country = "Spain Madrid Barcelona Valencia".split()
#Initialize a dictionary:
d = {}
#Create another list that only includes cities:
cities_list = country[1:]
#Create a nested list within a dictionary:
d[country[0]] = cities_list
Which would provide a nested dictionary such as {'Spain': ['Madrid', 'Barcelona', 'Valencia']}
And that's where I get really confused. It's clear that I need to access the nested list, but using d.values() only gives the following output
dict_values([['Madrid', 'Barcelona', 'Valencia']])
I'm clearly missing some fundamental info on the topic, but I've looked up here and in Eric Matthes's "Crash Course" but still couldn't find a solid solution.
Probably my initial approach is completely wrong? There's a couple of similar topics here too, but it seems none of them actually involves not just accessing a list (which I kinda understand: d."Spain"[0]) but also comparing an input to one of the list's values.
Any advice would be great anyways.

You are correct, to check if Madrid exists in your dictionary you can use for loop to check
city_to_be_searched = 'Madrid'
result = None
for k,v in d.items():
if city_to_be_searched in v:
result = k
if(result):
print(f'{city_to_be_searched} located in {result}')
else:
print('No data found')
Madrid located in Spain

After taking an input:
city_name = input()
You could do something like:
result = None
for key in d:
if city_name in d[key]:
result = f'{city_name} is located in {key}'
if result:
print(result)
else:
print('No data on input city')

You can iterate over the key, value pairs of a dictionary using items() method as:
city = "Madrid"
found = False
for key, value in d.items():
if city in value: # check if Madrid is in the values' list
print(f"{city} is located in {key}")
found = True
break
if not found:
print("No data on input city")
Output:
Madrid is located in Spain

Related

Python Max function - Finding highest value in a dictionary

My question is about finding highest value in a dictionary using max function.
I have a created dictionary that looks like this:
cc_GDP = {'af': 1243738953, 'as': 343435646, etc}
I would like to be able to simply find and print the highest GDP value for each country.
My best attempt having read through similar questions is as follows (I'm currently working through the Python crash course book at which the base of this code has been taken, note the get_country_code function is simply providing 2 letter abbreviations for the countries in the GDP_data json file):
#Load the data into a list
filename = 'gdp_data.json'
with open(filename) as f:
gdp_data = json.load(f)
cc_GDP` = {}
for gdp_dict in gdp_data:
if gdp_dict['Year'] == 2016:
country_name = gdp_dict['Country Name']
GDP_total = int(gdp_dict['Value'])
code = get_country_code(country_name)
if code:
cc_GDP[code] = int(GDP_total)
print(max(cc_GDP, key=lambda key: cc_GDP[key][1]))
This provides the following error 'TypeError: 'int' object is not subscriptable'
Note if leaving out the [1] in the print function, this does provide the highest key which relates to the highest value, but does not return the highest value itself which is what I wish to achieve.
Any help would be appreciated.
So you currently extract the key of the country that has the highest value with this line:
country_w_highest_val = max(cc_GDP, key=lambda key: cc_GDP[key]))
You can of course just look that up in the dictionary again:
highest_val = cc_GDP[contry_w_highest_val]
But simpler, disregard the keys completely, and just find the highest value of all values in the dictionary:
highest_val = max(cc_GDP.values())
How about something like this:
print max(cc_GDP.values())
That will give you the highest value but not the key.
The error is being cause because you need to look at the entire dictionary, not just one item. remove the [1] and then use the following line:
print(cc_GDP[max(cc_GDP, key=lambda key: cc_GDP[key])])
Your code currently just returns the dictionary key. You need to plug this key back into the dictionary to get the GDP.
You could deploy .items() method of dict to get key-value pairs (tuples) and process it following way:
cc_GDP = {'af': 1243738953, 'as': 343435646}
m = max(list(cc_GDP.items()), key=lambda x:x[1])
print(m) #prints ('af', 1243738953)
Output m in this case is 2-tuple, you might access key 'af' via m[0] and value 1243738953 via m[1].

Finding highest value in a dictionary

I'm new to programming and currently taking a CSC 110 class. Our assignment is to create a bunch functions that do all sorts of things with some data that is given. I have taken all that data and put it into a dictionary but I'm having some trouble getting the data I want out of it.
Here is my problem:
I have a dictionary that stores a bunch of countries followed by a list that includes their population and GDP. Formatted something like this
{'country': [population, GDP], ...}
My task is to loop through this and find the country with the highest population or GDP then print:
'The country with the highest population is ' + highCountry+\
' with a population of ' + format(highPop, ',.0f')+'.')
In order to do this I wrote this function (this one is specifically for highest population but they all look about the same).
def highestPop(worldInfo):
highPop = worldInfo[next(iter(worldInfo))][0] #Grabs first countries Population
highCountry = next(iter(worldInfo))#Grabs first country in worldInfo
for k,v in worldInfo.items():
if v[0] > highPop:
highPop = v[0]
highCountry = k
return highPop,highCountry
While this is working for me I gotta think there is an easier way to do this. Also I'm not 100% sure how [next(iter(worldInfo))] works. Does this just grab the first value it sees?
Thanks for your help in advance!
Edit: Sorry I guess I wasn't clear. I need to pass the countries population but also the countries name. So I can print both of them in my main function.
I think you're looking for this:
max(worldInfo.items(), key=lambda x: x[1][0])
This will return both the country name and its info. For instance:
('france', [100, 22])
The max() function can work on python "iterables" which is a fancy word for anything that can be cycled or looped through. Thus it cycles or loops through the thing you put into it and spits out the item that's the highest.
But how does it judge which tuple is highest? Which is higher: France or Germany? You have to specify a key (some specification for how to judge each item). The key=lambda etc specifies a function that given an item (x), judge that item based on x[1][0]. In this instance if the item is ('france', [100, 22]) then x[1][0] is 100. So the x[1][0] of each item is compared and the item with the highest one is returned.
The next() and iter() functions are for python iterators. For example:
mytuple = ("apple", "banana", "cherry")
myit = iter(mytuple)
print(next(myit)) #=> apple
print(next(myit)) #=> banana
print(next(myit)) #=> cherry
Use the max() function, like so:
max(item[0] for item in county_dict.values()) #use item[1] for GDP!
Also try storing the values not in a list ([a, b]) but in a tuple ((a, b)).
Edit: Like iamanigeeit said in the comments, this works to give you the country name as well:
max(data[0], country for country, data in country_dict.items())
An efficient solution to get the key with the highest value: you can use the max function this way:
highCountry = max(worldInfo, key=lambda k: worldInfo[k][0])
The key argument is a function that specifies what values you want to use to determine the max.max(data[0], country for country, data in country_dict.items())
And obviously :
highPop = worldInfo[highCountry][0]

Conditional checks for JSON key-value pairs being ignored

I am building a point feature class from a web call that returns JSON. The JSON is a bit sketchy in that sometimes keys do not exist in the record. I am trying to do this, once I have a valid JSON object:
#requests stuff above this
for i in jsonObj:
try:
if i['properties']['country']:
country = i['properties']['country']
else:
country = 'UNK'
print('Country name not found, using {}'.format(country))
except KeyError, e:
print('Key error: reason: {}'.format(str(e)))
pass
#then do all the arcpy FC creation stuff
The result is a whole bunch of key errors with "reason: 'country'" and instead of building those rows with the generic 'country' value of 'UNK', it will simply ignore them and build the feature class, leaving out those points.
I have taken out the try and left it as a conditional check, but it fails at the first row that lacks a 'country' key.
In summary, I'm just trying to check if a key-value pair exists; if it doesn't, assign a generic value of 'UNK' to the country variable.
It seems like part of the problem might be that if i['properties']['countries'] is checking for a value, but not the existence of the key itself? How might I more efficiently check for the existence of the key?
I have read Check if a given key already exists in a dictionary and have modified my code to both of these, and neither yield the expected outcome:
for i in jsonObj:
try:
# get coordinates first
if i['geometry']['coordinates']:
ycoord = float(i['geometry']['coordinates'][1])
xcoord = float(i['geometry']['coordinates'][0])
if i['properties']['city'] in i:
city = i['properties']['city']
else:
city = 'UNK'
if i['properties']['country'] in i:
country = i['properties']['country']
else:
country = 'UNK'
and
for i in jsonObj:
try:
# get coordinates first
if i['geometry']['coordinates']:
ycoord = float(i['geometry']['coordinates'][1])
xcoord = float(i['geometry']['coordinates'][0])
if 'city' in i:
city = i['properties']['city']
else:
city = 'UNK'
if 'country' in i:
country = i['properties']['country']
else:
country = 'UNK'
I do have the 'properties' key in every record/dictionary, but whether I have a 'country' key is not guaranteed. Some rows in the json response have it, some rows don't
Your last try:
if 'country' in i:
country = i['properties']['country']
else:
country = 'UNK'
was close, but you're managing a dict of dicts, and 'country' has better chance to be a key of the sub-dict, so the fix would be:
if 'country' in i['properties']:
country = i['properties']['country']
else:
country = 'UNK'
or even better & shorter using get with a default value (I recommend that last one over the quickfix):
country = i['properties'].get('country','UNK')
It seems like you don't fully understand json implementation.
x = i['geometry']['coordinates'] is basically y = i['geometry']; x = y['coordinates'], so you need safety check for each layer, becaue i['geometry'] not only will throw exception when 'geometry' field is not found but also the returned object must also implement [] for ['coordinates'] to work (so in this case it must be another json object, and not string,bool,None etc.)
I also believe your json object is implemented using python dictionary, so you can check if certain field, e.g. 'geometry' exists using x.get('geometry'), which will return either its value or None object. You can also use city = x.get('city', 'UKN') to set default value (json object, string, bool, None etc.) if it was not found in dict (python dict.get method implements default handler).
So in the end you should have something like this:
geo = i.get('geometry')
if not geo: return
coords = geo.get('coordinates')
if not coords: return
xcoord, ycoord = float(coords[0]), float(coords[1])
props = i.get('properties')
if not props: return
city = props.get('city', 'UNK')
country = props.get('country', 'UNK')
This is a draft and I did not test it, also this strongly asserts that your json object is based on python dict object.

Searching and manipulating lists in lists in Python

I have lists of names and cities and am trying to compile a list of the number of users in each city.
I want to have a list that looks like:
citylist = (['New York', 53], ['San Francisco', 23], ['Los Angeles', 54])
etc.
First problem I have is that when I read a new line from the file I need to check whether that city already exists. If it doesn't then I need to add it and give it the number 1. So I have tried:
if city not in citylist:
citylist.append([city, 1])
Problem with that is that even if the city is already in the list the search doesn't work as I guess it is typing to match the city to the entire element not just the first item of the element. Can someone tell me how to get round that please?
The seocnd part is lets assume that city is found somewhere in citylist, how can I then increment the number next to the city name by 1?
Thanks for any guidance.
Use a dictionary or collections.Counter here. List is not an appropriate data-structure for this task.
Normal dictionary example:
citydict = {'New York': 53,
'San Francisco': 23,
'Los Angeles': 54}
Now simply update the dictionary like this:
for line in file_obj:
city = #do something with line
citydict[city] = citydict.get(city, 0) + 1
python dict is a proper data structure for what you want to achive. Using defaultdict(int) you can also increment directly for a given city (key of the dict) even if it is not yet present in the dict.
Use a dictionary to maintain the counters
Here is a sample code:
citydict = {}
all_cities = open("cities.txt", "r").readlines()
for city in all_cities:
if citydict.has_key(city):
citydict[city] +=1
else:
citydict[city] = 1
print citydict.items()
As everyone else said, a dictionay is exactly the datastructure for this type of problems. But if you really want it as list (e.g. to understand how lists work), you can do it as follows:
def add_to_citylist(citylist, city):
"""modifies citylist according to spec"""
city_already_in_citylist = False
#iterate throuch citylists and get city-sub-list as c:
for c in citylist:
if c[0] == city:
#city found, so update count
c[1] += 1
#take a note that city was in list:
city_already_in_citylist = True
if not city_already_in_citylist:
#we did not find city in citylist --> add it
citylist.append([city, 1])
#your citylist should be a list (not a tuple (...) ) since a tuple is unmutable
citylist = [['New York', 53], ['San Francisco', 23], ['Los Angeles', 54]]
add_to_citylist(citylist, "Boston")
add_to_citylist(citylist, "New York")
print citylist
After understanding the idea, you can improve the code by using "return" in the loop which has a similar effect but is more effective since it terminats the loop after the element is found:
def add_to_citylist(citylist, city):
"""modifies citylist according to spec"""
#iterate throuch citylists and get city-sub-list as c:
for c in citylist:
if c[0] == city:
#city found, so update count
c[1] += 1
break
citylist.append([city, 1])

Printing from two dictionaries

states = {state, abbr}
cities = {abbr, capital}
I'd like to print out state, abbr, capital or some other order of the 3 values.
I tried inverting the key, value pair in states with:
inv_states = {state: abbr for abbr, state in states.items()}
for abbr, capital in sorted(inv_states.items()):
print(abbr, ':', capital)
Now I've got:
states = {abbr, state}
cities = {abbr, capital}
And then trying to create a new dict with (I don't fully understand the below code):
newDict = defaultdict(dict)
for abbr in (inv_states, cities):
for elem in abbr:
newDict[elem['index']].update(elem)
fullDict = newDict.values()
print(fullDict)
But I'm getting a string indices must be intergers error.
Little help please. Or am I completely on the wrong path? Thanks.
Assuming your data is in dictionaries, (which it is not in your example code). It should be pretty straightforward to pring out the data you are looking for
for state, abbr in states.items():
print('{0}, {1}, {2}'.format(state, abbr, cities[abbr]))

Categories