Printing from two dictionaries - python

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

Related

Access nested list within a dictionary

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

How to create a dictionary whose values are sets?

I'm working on an exercise that requires me to build two dictionaries, one whose keys are country names, and the values are the GDP. This part works fine.
The second dictionary is where I'm lost, as the keys are supposed to be the letters A‐Z and the values are sets of country names. I tried using a for loop, which I've commented on below, where the issue lies.
If the user enters a string with only one letter (like A), the program should print all the countries that begin with that letter. When you run the program, however, it only prints out one country for each letter.
The text file contains 228 lines. ie:
1:Qatar:98900
2:Liechtenstein:89400
3:Luxembourg:80600
4:Bermuda:69900
5:Singapore:59700
6:Jersey:57000
etc.
And here's my code.
initials = []
countries=[]
incomes=[]
dictionary={}
dictionary_2={}
keywordFile = open("raw.txt", "r")
for line in keywordFile:
line = line.upper()
line = line.strip("\n")
line = line.split(":")
initials.append(line[1][0]) # first letter of second element
countries.append(line[1])
incomes.append(line[2])
for i in range(0,len(countries)):
dictionary[countries[i]] = incomes[i]
this for loop should spit out 248 values (one for each country), where the key is the initial and the value is the country name. However, it only spits out 26 values (one country for each letter in the alphabet)
for i in range(0,len(countries)):
dictionary_2[initials[i]] = countries[i]
print(dictionary_2)
while True:
inputS = str(input('Enter an initial or a country name.'))
if inputS in dictionary:
value = dictionary.get(inputS, "")
print("The per capita income of {} is {}.".format((inputS.title()), value ))
elif inputS in dictionary_2:
value = dictionary_2.get(inputS)
print("The countries that begin with the letter {} are: {}.".format(inputS, (value.title())))
elif inputS.lower() in "quit":
break
else:
print("Does not exit.")
print("End of session.")
I'd appreciate any input leading me in the right direction.
Use defaultdict to make sure each value of your initials dict is a set, and then use the add method. If you just use = you'll be overwriting the initial keys value each time, defaultdict is an easier way of using an expression like:
if initial in dict:
dict[initial].add(country)
else:
dict[initial] = {country}
See the full working example below, and also note that i'm using enumerate instead of range(0,len(countries)), which i'd also recommend:
#!/usr/bin/env python3
from collections import defaultdict
initials, countries, incomes = [],[],[]
dict1 = {}
dict2 = defaultdict(set)
keywordFile = """
1:Qatar:98900
2:Liechtenstein:89400
3:Luxembourg:80600
4:Bermuda:69900
5:Singapore:59700
6:Jersey:57000
""".split("\n\n")
for line in keywordFile:
line = line.upper().strip("\n").split(":")
initials.append(line[1][0])
countries.append(line[1])
incomes.append(line[2])
for i,country in enumerate(countries):
dict1[country] = incomes[i]
dict2[initials[i]].add(country)
print(dict2["L"])
Result:
{'LUXEMBOURG', 'LIECHTENSTEIN'}
see: https://docs.python.org/3/library/collections.html#collections.defaultdict
The values for dictionary2 should be such that they can contain a list of countries. One option is to use a list as the values in your dictionary. In your code, you are overwriting the values for each key whenever a new country with the same initial is to be added as the value.
Moreover, you can use the setdefault method of the dictionary type. This code:
dictionary2 = {}
for country in countries:
dictionary2.setdefault(country[0], []).append(country)
should be enough to create the second dictionary elegantly.
setdefault, either returns the value for the key (in this case the key is set to the first letter of the country name) if it already exists, or inserts a new key (again, the first letter of the country) into the dictionary with a value that is an empty set [].
edit
if you want your values to be set (for faster lookup/membership test), you can use the following lines:
dictionary2 = {}
for country in countries:
dictionary2.setdefault(country[0], set()).add(country)
Here's a link to a live functioning version of the OP's code online.
The keys in Python dict objects are unique. There can only ever be one 'L' key a single dict. What happens in your code is that first the key/value pair 'L':'Liechtenstein' is inserted into dictionary_2. However, in a subsequent iteration of the for loop, 'L':'Liechtenstein' is overwritten by 'L':Luxembourg. This kind of overwriting is sometimes referred to as "clobbering".
Fix
One way to get the result that you seem to be after would be to rewrite that for loop:
for i in range(0,len(countries)):
dictionary_2[initials[i]] = dictionary_2.get(initials[i], set()) | {countries[i]}
print(dictionary_2)
Also, you have to rewrite the related elif statement beneath that:
elif inputS in dictionary_2:
titles = ', '.join([v.title() for v in dictionary_2[inputS]])
print("The countries that begin with the letter {} are: {}.".format(inputS, titles))
Explanation
Here's a complete explanation of the dictionary_2[initials[i]] = dictionary_2.get(initials[i], set()) | {countries[i]} line above:
dictionary_2.get(initials[i], set())
If initials[i] is a key in dictionary_2, this will return the associated value. If initials[i] is not in the dictionary, it will return the empty set set() instead.
{countries[i]}
This creates a new set with a single member in it, countries[i].
dictionary_2.get(initials[i], set()) | {countries[i]}
The | operator adds all of the members of two sets together and returns the result.
dictionary_2[initials[i]] = ...
The right hand side of the line either creates a new set, or adds to an existing one. This bit of code assigns that newly created/expanded set back to dictionary_2.
Notes
The above code sets the values of dictionary_2 as sets. If you want to use list values, use this version of the for loop instead:
for i in range(0,len(countries)):
dictionary_2[initials[i]] = dictionary_2.get(initials[i], []) + [countries[i]]
print(dictionary_2)
You're very close to what you're looking for, You could populate your dictionaries respectively while looping over the contents of the file raw.txt that you're reading. You can also read the contents of the file first and then perform the necessary operations to populate the dictionaries. You could achieve your requirement with nice oneliners in python using dict comprehensions and groupby. Here's an example:
country_per_capita_dict = {}
letter_countries_dict = {}
keywordFile = [line.strip() for line in open('raw.txt' ,'r').readlines()]
You now have a list of all lines in the keywordFile as follows:
['1:Qatar:98900', '2:Liechtenstein:89400', '3:Luxembourg:80600', '4:Bermuda:69900', '5:Singapore:59700', '6:Jersey:57000', '7:Libya:1000', '8:Sri Lanka:5000']
As you loop over the items, you can split(':') and use the [1] and [2] index values as required.
You could use dictionary comprehension as follows:
country_per_capita_dict = {entry.split(':')[1] : entry.split(':')[2] for entry in keywordFile}
Which results in:
{'Qatar': '98900', 'Libya': '1000', 'Singapore': '59700', 'Luxembourg': '80600', 'Liechtenstein': '89400', 'Bermuda': '69900', 'Jersey': '57000'}
Similarly using groupby from itertools you can obtain:
from itertools import groupby
country_list = country_per_capita_dict.keys()
country_list.sort()
letter_countries_dict = {k: list(g) for k,g in groupby(country_list, key=lambda x:x[0]) }
Which results in the required dictionary of initial : [list of countries]
{'Q': ['Qatar'], 'S': ['Singapore'], 'B': ['Bermuda'], 'L': ['Luxembourg', 'Liechtenstein'], 'J': ['Jersey']}
A complete example is as follows:
from itertools import groupby
country_per_capita_dict = {}
letter_countries_dict = {}
keywordFile = [line.strip() for line in open('raw.txt' ,'r').readlines()]
country_per_capita_dict = {entry.split(':')[1] : entry.split(':')[2] for entry in keywordFile}
country_list = country_per_capita_dict.keys()
country_list.sort()
letter_countries_dict = {k: list(g) for k,g in groupby(country_list, key=lambda x:x[0]) }
print (country_per_capita_dict)
print (letter_countries_dict)
Explanation:
The line:
country_per_capita_dict = {entry.split(':')[1] : entry.split(':')[2] for entry in keywordFile}
loops over the following list
['1:Qatar:98900', '2:Liechtenstein:89400', '3:Luxembourg:80600', '4:Bermuda:69900', '5:Singapore:59700', '6:Jersey:57000', '7:Libya:1000', '8:Sri Lanka:5000'] and splits each entry in the list by :
It then takes the value at index [1] and [2] which are the country names and the per capita value and makes them into a dictionary.
country_list = country_per_capita_dict.keys()
country_list.sort()
This line, extracts the name of all the countries from the dictionary created before into a list and sorts them alphabetically for groupby to work correctly.
letter_countries_dict = {k: list(g) for k,g in groupby(country_list, key=lambda x:x[0]) }
This lambda expression takes the input as the list of countries and groups together the names of countries where each x starts with x[0] into list(g).

Build a List of Tuples from a Dict

I have a list y of keys from a dictionary that is derived from a call to the Google Places API.
I would like to build a list of tuples for each point of interest:
lst = []
for i in range(len(y)):
lst.append((y[i]['name'], y[i]['formatted_address'], y[i]['opening_hours']['open_now'], y[i]['rating']))
This works if the field is in the list and I receive a list of results that look like the one below, which is exactly what I want:
("Friedman's", '1187 Amsterdam Ave, New York, NY 10027, USA', True, 4.2)
However, the script throws an error if a desired field is not in the list y. How can I build a list of tuples that checks whether the desired field is in y before building the tuple?
Here's what I've tried:
for i in range(len(y)):
t = ()
if y[i]['name']:
t = t + lst.append(y[i]['name'])
if y[i]['formatted_address']:
t = t + lst.append(y[i]['formatted_address'])
if y[i]['opening_hours']['open_now']:
t = t + lst.append(y[i]['opening_hours']['open_now'])
if y[i]['rating']:
t = t + lst.append(y[i]['rating'])
lst.append(t)
However, this doesn't work and seems very inelegant. Any suggestions?
This list comprehension uses default values when one of the keys is not present (using dict.get()). I added variables so you can set the desired default values.
default_name = ''
default_address = ''
default_open_now = False
default_rating = 0.0
new_list = [
(
e.get('name', default_name),
e.get('formatted_address', default_address),
e.get('opening_hours', {}).get('open_now', default_open_now),
e.get('rating', default_rating),
)
for e in y]
For a start, you should almost never loop over range(len(something)). Always iterate over the thing directly. That goes a long way to making your code less inelegant.
For the actual issue, you could loop over the keys and only add the item if it is in the dict. That gets a bit more complicated with your one element that is a nested lookup, but if you take it out then your code just becomes:
for item in y:
lst.append(tuple(item[key] for key in ('name', 'formatted_address', 'opening_hours', 'rating') if key in item))
You can use the get feature from dict.
y[i].get('name')
if y[i] has key 'name' returns the value or None. For nested dicts, use default value from get.
y[i].get('opening_hours', {}).get('open_now')
For data structure, I recommend to keep it as an dict, and add dicts to an list.
lst = []
lst.append({'name': "Friedman's", "address": '1187 Amsterdam Ave, New York, NY 10027, USA'})
Try this:
for i in y:
lst.append((v for k,v in i.items()))
you can use the keys method to find the keys in a dict. In your case:
lst=[]
fields = ('name', 'formatted_address', 'opening_hours' 'open_now', 'rating')
for i in range(len(y)):
data = []
for f in fields:
if f in y[].keys():
data.append(y[i][f])
else:
data.append(None)
lst.append(set(data))
note that you can also get all the key, value pairs in a dict using the items() method. That would actually simply the code a bit. To make it even better, itterate over the set, rather than calling len(set) to:
lst=[]
fields = ('name', 'formatted_address', 'opening_hours' 'open_now', 'rating')
for i in y:
data = []
for key, value in i.items():
if key in fields:
data.append(value)
else:
data.append(None)
lst.append(set(data))

Extract value from list add to dictionary

I have a list of lists such as pa_l = [[ABU, XXXXX, 0],[AZE, CCCCC,0]]. This pa_l contains 243 lists. iso_pa is a list with only country codes, such as:
ABU and AZE (plus others)
I need to create a dictionary all_countries = {} where each country code has its name. For this I have created the following code:
for i in iso_pa:
if i not in all_countries.keys():
all_countries[i] = pa_l[i][1]
But this is not working. I would be pleased if someone could help me.
for i in range (len (iso_pa)):
if iso_pa [i] not in all_countries.keys():
all_countries [iso_pa [i]] = pa_l [i][1]
As you have stated, you want to prepare a dictionary where country_code maps to a country name. There is a small fix for that in our code:
for i in iso_pa:
if i not in all_countries:
all_countries[i[0]] = i[1]
The list of lists is not really a good structure for looking up the codes that you have in the iso_pa list. So turn that longer list into a dictionary first, and then pick from that the names that you need in the result:
dict_pa_l = dict([lst[0:2] for lst in pa_l])
all_countries = [{code: dict_pa_l[code]} for code in iso_pa]
You can use itertools.groupby format pa_l such that it will be simpler to access the first occurrence of the country and its code:
import itertools
pa_l = [['ABU', 'XXXXX', 0],['AZE', 'CCCCC',0]]
new_data = {a:list(b)[0][-1] for a, b in itertools.groupby(sorted(pa_l, key=lambda x:x[0]), key=lambda x:x[0])}
Output:
{'ABU': 0, 'AZE': 0}

How to Re-arrange items in a Python Dictionary during For Loop?

I am building a Python dictionary from a table in Excel. It's a Category:Name relationship. So, the first column in the spreadsheet is a category and the second column is the name of a file:
Forests - Tree Type
Forests - Soil Type
Administrative - Cities
Administrative - Buildings
Mineral - Gold
Mineral - Platinum
Water - Watershed
Water - Rivers
Water - Lakes
Water - Streams
and so on...
I use this code to build the dictionary:
layerListDict = dict()
for row in arcpy.SearchCursor(xls):
# Set condition to pull out the Name field in the xls file.
# LayerList being the list of all the 'Name' from the 'Name' column built earlier in the script
if str(row.getValue("Name")).rstrip() in layerList:
# Determine if the category item is in the dictionary as a key already. If so, then append the Name to the list of values associated with the category
if row.getValue("Category") in layerListDict:
layerListDict[row.getValue("Category")].append(str(row.getValue("Name")))
# if not, create a new category key and add the associated Name value to it
else:
layerListDict[row.getValue("Category")] = [str(row.getValue("Name"))]
So, now I have a dictionary with Category as the key and a list of Names as the values:
{u'Forests': ['Tree Type', 'Soil Type'], u'Administrative': ['Cities', 'Buildings'], u'Mineral': ['Gold', 'Platinum'], u'Water': ['Watershed', 'Rivers', 'Lakes', 'Streams']}
I can now iterate over the sorted dictionary by key:
for k,v in sorted(layerListDict.iteritems()):
print k, v
PROBLEM: What I would like to do is to iterate over the sorted dictionary with one caveat...I wanted to have the 'Mineral' key to be the very first key and then have the rest of the keys print out in alphabetical order like this:
Mineral ['Gold', 'Platinum']
Administrative ['Cities', 'Buildings']
Forests ['Tree Type', 'Soil Type']
Water ['Watershed', 'Rivers', 'Lakes', 'Streams']
Can anyone suggest how I can accomplish this?
I tried to set a variable to a sorted list, but it returns as a python list and I cannot iterate over the Python list by a key value pair anymore.
List2 = sorted(layerListDict.iteritems())
[u'Forests':['Tree Type', 'Soil Type'], u'Administrative': ['Cities', 'Buildings'], u'Mineral': ['Gold', 'Platinum'], u'Water': ['Watershed', 'Rivers', 'Lakes', 'Streams']]
print "Mineral", layerListDict.pop("Mineral")
for k, v in sorted(layerListDict.iteritems()):
print k, v
If you don't want to modify layerListDict:
print "Mineral", layerListDict["Mineral"]
for k, v in sorted(layerListDict.iteritems()):
if k != "Mineral":
print k, v
An overly general solution:
import itertools
first = 'Mineral'
for k, v in itertools.chain([(first, layersListDict[first])],
((k,v) for (k,v) in layerListDict.iteritems() if k != first)):
print k, v
or closer to my original incorrect solution:
for k, layersListDict[k] in itertools.chain((first,),
(k for k in layerListDict
if k != first)):
print k, v
If you're just looking to print the key-value pairs, then the other solutions get the job done quite well. If you're looking for the resulting dictionary to have a certain order so that you can perform other operations on it, you should look into the OrderedDict class:
https://docs.python.org/2/library/collections.html#collections.OrderedDict
Objects are stored in the order that they are inserted. In your case, you would do something similar to the other answers first to define the order:
dict_tuples = sorted(layerListDict.items())
ordered_tuples = [("Mineral", layerListDict["Mineral"],)]
ordered_tuples += [(k, v,) for k, v in dict_tuples if k != "Mineral"]
ordered_dict = collections.OrderedDict(ordered_tuples) #assumes import happened above
Now you can do whatever you want with ordered_dict (careful with deleting then reinserting, see the link above). Don't know if that helps you more than some of the other answers (which are all pretty great!).
EDIT: Whoops, my recollection of the update behavior of OrderedDicts was a bit faulty. Fixed above. Also streamlined the code a little. You could potentially generate the tuples in your first for loop and then put them in the OrderedDict, too.
EDIT 2: Forgot that tuples are naturally sorted by the first element (thanks John Y), removed the unnecessary key param in the sorted() call.
Keep a list of keys in the order you want to iterate over the map. Then iterate through the list, using the values as keys into the map.
Actually, after seeing the other solutions, I like chepner's answer with itertools.chain() better, especially if the list of keys is large, because mine will move things around in the list too much.
# sort the keys
keyList = sorted(keys(layerListDict))
# remove 'Mineral' from it's place
del keyList[keyList.index('Mineral')]
# Put it in the beginning
keyList = ['Mineral'] + keyList
# Iterate
for k in keyList:
for v in layerListDict[k]:
print k, v
Second shot at an answer. This is pretty different from my original, and makes some possibly wrong assertions, but I like the feel of it a lot better. Since you're able to determine all of the values in the "name" column (layerList), I'm going to assume you can do the same for the "categories" column. This code assumes you've placed your categories (including "Mineral") into an unsorted list called categories, and replaces the original code:
categories.sort()
categories = ["Mineral"] + [cat for cat in categories if cat != "Mineral"]
# Insert the categories into our dict with placeholder lists that we can append to
layerListDict = collections.OrderedDict([(cat, [],) for cat in categories])
for row in arcpy.SearchCursor(xls):
if str(row.getValue("Name")).rstrip() in layerList:
layerListDict[row.getValue("Category")].append(str(row.getValue("Name")))
Now you can just iterate over layerListDict.items().

Categories