Dictionaries are very similar to Hashtable or HashMap in Java, it is also called associative arrays in other programming languages. The basic principle of Dictionary is that it stores key-value pairs.
This is very widely used concept in computer science, think of product bar code (key) that maps to the product (value), or phone number (key) that maps to a person's account (value)
The key of a dictionary can be a number, string or several other immutable objects
This is very widely used concept in computer science, think of product bar code (key) that maps to the product (value), or phone number (key) that maps to a person's account (value)
The key of a dictionary can be a number, string or several other immutable objects
>>> d={"Zain":7, "Tanisha":7, "Oliver":7, "Amelia":5, "Annika":1} >>> >>> d {'Zain': 7, 'Tanisha': 7, 'Oliver': 7, 'Amelia': 5, 'Annika': 1}
you access a dictionary item like you would access list element, except in place of the index, you would use a dictionary key
>>> d["Zain"] 7 >>> d["Annika"] 1
passing a key that does not exist returns an error:
>>> d["Fiona"] Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'Fiona'
To mitigate that, either use in operator to first check if key exists, or use get() method. In the example below, if "Fiona" is found, then the matching dictionary entry is returned, otherwise the "None Found" is returned
>>> d={"Zain":7, "Tanisha":7, "Oliver":7, "Amelia":5, "Annika":1} >>> d.get("Fiona", "None Found") 'None Found' >>> d {'Zain': 7, 'Tanisha': 7, 'Oliver': 7, 'Amelia': 5, 'Annika': 1}
Let's talk little more about dictionary keys and values, which ones of these do you think will work?
>>> nd={(1,):"1", (1,2):"2"}
>>> nd={1:1, 2:2, 3:3}
>>> nd={[1]:1, [2]:2, [3]:3}
>>> nd={{1}:1, {2}:2, {3}:3}
To add an element, add it by specifying key and value:
>>> d {'Zain': 7, 'Tanisha': 7, 'Oliver': 7, 'Amelia': 5, 'Annika': 1, 'Fiona': 6} >>> d["Tommy"]=100 >>> d {'Zain': 7, 'Tanisha': 7, 'Oliver': 7, 'Amelia': 5, 'Annika': 1, 'Fiona': 6, 'Tommy': 100}
Do you think dictionary is ordered collection?
Do you think dictionary is mutable?
>>> d {'Zain': 7, 'Tanisha': 7, 'Oliver': 7, 'Amelia': 5, 'Annika': 1, 'Fiona': 6, 'Tommy': 100} >>> len(d) 7
keys() method returns the iterable over the dictionary keys
d={"Zain":7, "Tanisha":7, "Oliver":7, "Amelia":5, "Annika":1} for i in d.keys(): print(i)
Zain Tanisha Oliver Amelia Annika
Similarly, values() method returns iterable over the values:
d={"Zain":7, "Tanisha":7, "Oliver":7, "Amelia":5, "Annika":1} for i in d.values(): print(i)
7 7 7 5 1
You can convert keys, values, and items into lists. Items method returns tuples of key-value pairs
>>> list(d.keys()) ['Oliver', 'Annika', 'Amelia', 'Zain', 'Tommy', 'Tanisha'] >>> tuple(d.keys()) ('Oliver', 'Annika', 'Amelia', 'Zain', 'Tommy', 'Tanisha') >>> tuple(d.values()) (7, 1, 5, 7, 2, 7) >>> list(d.values()) [7, 1, 5, 7, 2, 7] >>> list(d.items()) [('Oliver', 7), ('Annika', 1), ('Amelia', 5), ('Zain', 7), ('Tommy', 2), ('Tanisha', 7)]
More examples of looping through dictionaries:
dict1 = { "first_name":"Gula", "last_name":"Nurmatova", "state":"CT", } for item in dict1.items(): print(item)
('first_name', 'Gula') ('last_name', 'Nurmatova') ('state', 'CT')
dict1 = { "first_name":"Gula", "last_name":"Nurmatova", "state":"CT", } for key in dict1.keys(): print(key) print(dict1[key])
first_name Gula last_name Nurmatova state CT
Weather API response parsing
import pprint as pp weather = {"coord":{"lon":-0.13,"lat":51.51},"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],"base":"stations","main":{"temp":291.46,"feels_like":289.23,"temp_min":289.82,"temp_max":292.59,"pressure":1017,"humidity":72},"visibility":10000,"wind":{"speed":4.6,"deg":60},"clouds":{"all":100},"dt":1600506465,"sys":{"type":1,"id":1414,"country":"GB","sunrise":1600494141,"sunset":1600538770},"timezone":3600,"id":2643743,"name":"London","cod":200} pp.pprint(weather)
Output:
{'base': 'stations', 'clouds': {'all': 100}, 'cod': 200, 'coord': {'lat': 51.51, 'lon': -0.13}, 'dt': 1600506465, 'id': 2643743, 'main': {'feels_like': 289.23, 'humidity': 72, 'pressure': 1017, 'temp': 291.46, 'temp_max': 292.59, 'temp_min': 289.82}, 'name': 'London', 'sys': {'country': 'GB', 'id': 1414, 'sunrise': 1600494141, 'sunset': 1600538770, 'type': 1}, 'timezone': 3600, 'visibility': 10000, 'weather': [{'description': 'overcast clouds', 'icon': '04d', 'id': 804, 'main': 'Clouds'}], 'wind': {'deg': 60, 'speed': 4.6}}
Let's parse out the "temp" value:
weather["main"]["temp"]
we get back the temperature in Kelvin 291.46
weather = {"coord":{"lon":-0.13,"lat":51.51},"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],"base":"stations","main":{"temp":291.46,"feels_like":289.23,"temp_min":289.82,"temp_max":292.59,"pressure":1017,"humidity":72},"visibility":10000,"wind":{"speed":4.6,"deg":60},"clouds":{"all":100},"dt":1600506465,"sys":{"type":1,"id":1414,"country":"GB","sunrise":1600494141,"sunset":1600538770},"timezone":3600,"id":2643743,"name":"London","cod":200} print("Temperature in Kelvin:") temp_kelv = weather["main"]["temp"] print(temp_kelv) print("Temperature in Fahrenheit:") temp_fahr = (temp_kelv - 273.15) * 9/5 + 32 print(temp_fahr)
Temperature in Kelvin: 291.46 Temperature in Fahrenheit: 64.958
Use copy method to shallow copy a dictionary (plain python, no need to import anything):
>>> d = {"one":1, "two":2, "three":3} >>> d {'one': 1, 'two': 2, 'three': 3} >>> d2=d.copy() >>> d2 {'one': 1, 'two': 2, 'three': 3}
let's look at the effect of such copy
>>> d = {"one":[1, "one", 1.0], "two":[2, "two", 2.0], "three":[3, "three", 3.0]} >>> d {'one': [1, 'one', 1.0], 'two': [2, 'two', 2.0], 'three': [3, 'three', 3.0]} >>> d2=d.copy() >>> d2 {'one': [1, 'one', 1.0], 'two': [2, 'two', 2.0], 'three': [3, 'three', 3.0]}
>>> d2["one"][0] = 100 >>> d {'one': [100, 'one', 1.0], 'two': [2, 'two', 2.0], 'three': [3, 'three', 3.0]}
You can use deepcopy on dictionaries:
>>> import copy >>> d = {"one":[1, "one", 1.0], "two":[2, "two", 2.0], "three":[3, "three", 3.0]} >>> d3=copy.deepcopy(d) >>> d3 {'one': [1, 'one', 1.0], 'two': [2, 'two', 2.0], 'three': [3, 'three', 3.0]}
update() method updates the leftmost dictionary with all entries of rightmost dictionary:
>>> d={"Zain":7, "Annika":1} >>> n={"Oliver":7, "Zain":8} >>> d.update(n) >>> d {'Oliver': 7, 'Annika': 1, 'Zain': 8}
Look at the code below, what conclusions can you make?
>>> a={} >>> type(a) <class 'dict'> >>> a={1,2,3} >>> type(a) <class 'set'>
SETS AND DICTIONARIES COMPREHENTIONS
Dictionaries and sets have their own equivalents of list comprehensions.
These make it easy to create derivative data structures when writing algorithms.
These make it easy to create derivative data structures when writing algorithms.
>>> chile_ranks = {'ghost': 1, 'habanero': 2, 'cayenne': 3} >>> rank_dict = {rank: name for name, rank in chile_ranks.items()} >>> rank_dict {1: 'ghost', 2: 'habanero', 3: 'cayenne'}
>>> rank_dict {1: 'ghost', 2: 'habanero', 3: 'cayenne'} >>> rank_dict.values() dict_values(['ghost', 'habanero', 'cayenne']) >>> chile_len_set = {len(name) for name in rank_dict.values()} >>> chile_len_set {8, 5, 7}
>>> chile_len_list = [len(name) for name in rank_dict.values()] >>> chile_len_list [5, 8, 7]
For example if we wanted to convert a dictionary of temperatures from K to F:
import pprint as pp temps={'temp': 291.46, 'temp_max': 292.59, 'temp_min': 289.82} temps_fahr = {key: (val - 273.15) * 9/5 + 32 for key, val in temps.items()} pp.pprint(temps_fahr)
{'temp': 64.958, 'temp_max': 66.99199999999999, 'temp_min': 62.00600000000003}
STRING FORMATTING
format() method:
You can use either % or parameter indexes in {} to format the strings
You can use either % or parameter indexes in {} to format the strings
>>> s="{0} has the best {1} in the {2}" >>> s.format("UNH", "students", "Connecticut") 'UNH has the best students in the Connecticut'
or variables and assigned values:
>>> s="{state} has the best {institution} in the {country}" >>> s.format(state="Connecticut", institution="banks", country="US") 'Connecticut has the best banks in the US'
or:
>>> s = "{} and {}".format("war", "peace") >>> s 'war and peace'
Any data types, such as numbers, tuples, lists, boolean, etc can be used
Format specifiers let you set alignments.
If the string is longer than the padding, the string will continue (will not get chopped off)
>>> s="{state:20} has the best {institution:20} in the {country:15}" >>> s.format(state="Connecticut", institution="banks", country="US") 'Connecticut has the best banks in the US '
To truncate a long string:
The number behind a . in the format specifies the precision of the output.
The number behind a . in the format specifies the precision of the output.
>>> '{:.5}'.format('xylophone') 'xylop'
Combining truncating and padding:
>>> '{:10.5}'.format('xylophone') 'xylop ' >>> '{:*>10.5}'.format('xylophone') '*****xylop'
< - align to the left
> - align to the right
>>> s="The price will be {price:<10}" >>> s.format(price="$5") 'The price will be $5 ' >>> s="The price will be {price:>10}" >>> s.format(price="$5") 'The price will be $5'
{institution:*>20} - alight to the right and fill in the spaces with *
>>> s="The price will be {price:.>10}" >>> s.format(price="$5") 'The price will be ........$5'
^ centers the formatted value
>>> '{:^10}'.format('test') ' test '
Formatting numbers:
>>> '{:d}'.format(42) '42' >>> '{:6d}'.format(42) ' 42' >>> '{:6.2f}'.format(3.141592653589793) ' 3.14' >>> '{:06.2f}'.format(3.141592653589793) '003.14'
if the number doesn't fit into padding, the value is still preserved
>>> '{:02.2f}'.format(3.141592653589793)
'3.14'
Formatting with % (the old formatting method)
%s - format string
%i - format integer
%f - format float
<%-6.2f> - align a floating point number to the left, allocate 6 spaces for the part before the . and 2 spaces for the part after the .
- means align to the left
no - would align to the right
>>> '{:02.2f}'.format(3.141592653589793)
'3.14'
Formatting with % (the old formatting method)
%s - format string
%i - format integer
%f - format float
<%-6.2f> - align a floating point number to the left, allocate 6 spaces for the part before the . and 2 spaces for the part after the .
- means align to the left
no - would align to the right
>>> "Pi is <%-6.2f>" % 3.14159 'Pi is <3.14 >' >>> "Pi is <%-7.2f>" % 3.14159 'Pi is <3.14 >' >>> "Pi is <%7.2f>" % 3.14159 'Pi is < 3.14>'
Similarly for int:
>>> "the price will be $%7i" % 5 'the price will be $ 5' >>> "the price will be $%-7i" % 5 'the price will be $5 '
Let's use the format method to reformat our temperatures:
temps={'temp': 291.46, 'temp_max': 292.59, 'temp_min': 289.82} temps_fahr = {key: (val - 273.15) * 9/5 + 32 for key, val in temps.items()} strings = {"{} is {:.2f} F".format(key, val) for key, val in temps_fahr.items()} for s in strings: print(s)
temp is 64.96 F temp_min is 62.01 F temp_max is 66.99 F
FUNCTIONS
Functions can be defined anywhere in the code but can be called only after they are declared
the general syntax for defining a function is:
def <function name>(<parameter name1>, <parameter name2>, ....):
<function body>
you'd call this function with
<function name>(argument1)
Here is an example of a function and a call to it:
the general syntax for defining a function is:
def <function name>(<parameter name1>, <parameter name2>, ....):
<function body>
you'd call this function with
<function name>(argument1)
Here is an example of a function and a call to it:
def return_passed_value(param1): return param1 s = return_passed_value(5) print(s)
$ python example.py 5
If a function does not have an explicit return statement then it returns None (equivalent to null)
def return_passed_value(param1): print("inside function") s = return_passed_value(5) print(s)
$ python example.py inside function None
In Python, the Immutable objects - Strings, Tuples, numbers, etc will act as if they are passed by value (i.e. what is done to them inside function has no effect outside), however that is not truly the case, please see examples and visualization below
def change_value(s): s = s*10 print("Inside function value is {} ".format(s)) s = 5 change_value(s) print("Outside function value is {}".format(s))
$ python example.py Inside function value is 50 Outside function value is 5
def change_value(s): s = " new string" print("Inside function value is {} ".format(s)) s = " some string" change_value(s) print("Outside function value is {}".format(s))
$ python example.py Inside function value is new string Outside function value is some string
def change_value(s): s = (5,6,7) print("Inside function value is {} ".format(s)) s = (1,2,3) change_value(s) print("Outside function value is {}".format(s))
$ python example.py Inside function value is (5, 6, 7) Outside function value is (1, 2, 3)
Now, let's take a look at what happens with mutable lists, the passing is same as with tuples, they are passed by reference
def change_value(s): s = [5,6,7] print("Inside function value is {} ".format(s)) s = [1,2,3] change_value(s) print("Outside function value is {}".format(s))
$ python example.py Inside function value is [5, 6, 7] Outside function value is [1, 2, 3]
However here is where you will see a different behavior
NESTED FUNCTIONS
def outer(): def inner(): print("inside inner") print("inside outer") inner()#works outer() #works #inner() #won't work - invisible to main scope
$ python example.py inside outer inside inner
HOMEWORK
program 1:
Write a function that converts temperature from Fahrenheit to Celsius using formula
Tc=(5/9)*(Tf-32)
To test your answer, 68F = 20C
program 2:
Write a function count_frequency that takes a list of words as an argument, counts how many times each word appears in the list, and then returns this frequency listing as a Python dictionary
Sample function call and output:
mylist=["one", "two","eleven", "one", "three", "two", "eleven", "three", "seven", "eleven"]
print(count_frequency(mylist))
{'seven': 1, 'one': 2, 'eleven': 3, 'three': 2, 'two': 2}
additional independent research, understand how Counter can be used. You do not need to submit anything, but there will be a question in the next week's quiz covering this topic
program 3:
leetcode two sum: https://leetcode.com/problems/two-sum/
Write a function that converts temperature from Fahrenheit to Celsius using formula
Tc=(5/9)*(Tf-32)
To test your answer, 68F = 20C
program 2:
Write a function count_frequency that takes a list of words as an argument, counts how many times each word appears in the list, and then returns this frequency listing as a Python dictionary
Sample function call and output:
mylist=["one", "two","eleven", "one", "three", "two", "eleven", "three", "seven", "eleven"]
print(count_frequency(mylist))
{'seven': 1, 'one': 2, 'eleven': 3, 'three': 2, 'two': 2}
additional independent research, understand how Counter can be used. You do not need to submit anything, but there will be a question in the next week's quiz covering this topic
program 3:
leetcode two sum: https://leetcode.com/problems/two-sum/
program 4 (up to 3.3 points extra credit for quality of research):
design URL shortener, similar to bit.ly
You need to build a URL shortener, similar to https://bitly.com/
On the bottom of the bitly URL above, you can paste a long URL and it will generate a short URL
For this program you will need to write two functions:
shorten_url function: takes a long URL and generates and returns a short URL - the short URL doesn't need to match the one on the bitly page, it should be just a shorter than the original URL
get_original_url function: takes a short URL as input and returns original long URL, if the short URL not found, return "HTTP 404" string instead
You will need to come up with the URL shortening mechanism, it is up to you what method you will use, but you must go through the following options and discuss in the comments of your program submission the pro's and con's of each of these methods. The correctness of your reasoning will not be graded. As you discuss pro's and con's think through chances of possible clashes of the shortened URL's, how many URL's will you be able to shorten total using the method and how much memory you think you will need to store all the short and matching long URL's. You can make and state your assumptions in the comments as well, for example you may assume an average length of a long URL to be 500 characters
1. uuid: https://docs.python.org/3/library/uuid.html
2. timestamp: https://realpython.com/python-time-module/#python-time-in-seconds-as-a-floating-point-number
3. MD5 hash: https://www.geeksforgeeks.org/md5-hash-python/
4. Another short string generation mechanism either your own or some other than above 3 python functions
On the bottom of the bitly URL above, you can paste a long URL and it will generate a short URL
For this program you will need to write two functions:
shorten_url function: takes a long URL and generates and returns a short URL - the short URL doesn't need to match the one on the bitly page, it should be just a shorter than the original URL
get_original_url function: takes a short URL as input and returns original long URL, if the short URL not found, return "HTTP 404" string instead
You will need to come up with the URL shortening mechanism, it is up to you what method you will use, but you must go through the following options and discuss in the comments of your program submission the pro's and con's of each of these methods. The correctness of your reasoning will not be graded. As you discuss pro's and con's think through chances of possible clashes of the shortened URL's, how many URL's will you be able to shorten total using the method and how much memory you think you will need to store all the short and matching long URL's. You can make and state your assumptions in the comments as well, for example you may assume an average length of a long URL to be 500 characters
1. uuid: https://docs.python.org/3/library/uuid.html
2. timestamp: https://realpython.com/python-time-module/#python-time-in-seconds-as-a-floating-point-number
3. MD5 hash: https://www.geeksforgeeks.org/md5-hash-python/
4. Another short string generation mechanism either your own or some other than above 3 python functions
optional program 5: Design LRU cache, leetcode
We will review this program in the class, however it would be beneficial if you try to solve it yourself
https://leetcode.com/problems/lru-cache/solution/
There is a solution here: https://www.nurmatova.com/dictionaries.html but please try to solve it before looking at the solutions
https://leetcode.com/problems/lru-cache/solution/
There is a solution here: https://www.nurmatova.com/dictionaries.html but please try to solve it before looking at the solutions