A dict
is a mapping of key-value pairs
python
states = {
"CA": "California",
"DE": "Delaware",
"NY": "New York",
"TX": "Texas",
"WY": "Wyoming"
}
Dictionaries support similar operations as lists/strings:
python
>>> len(states)
5
python
>>> "CA" in states
True
python
>>> "ZZ" in states
False
python
words = {
"más": "more",
"otro": "other",
"agua": "water"
}
Ways to access a value by key:
python
>>> words["otro"]
'other'
python
>>> first_word = "agua"
>>> words[first_word]
'water'
python
>>> words["pavo"]
KeyError: pavo
python
>>> words.get("pavo", "🤔")
'🤔'
python
spiders = {
"smeringopus": {
"name": "Pale Daddy Long-leg",
"length": 7
},
"holocnemus pluchei": {
"name": "Marbled cellar spider",
"length": (5, 7)
}
}
python
insects = {"spiders": 8, "centipedes": 100, "bees": 6}
for name in insects:
print(insects[name])
What will be the order of items?
basic
8 100 6
Keys are iterated over in the order they are first added.
General syntax:
python
{key: value for <name> in <iter exp>}
Example:
python
{x: x*x for x in range(3,6)}
python
def prune(d, keys):
"""Return a copy of D which only contains key/value pairs
whose keys are also in KEYS.
>>> prune({"a": 1, "b": 2, "c": 3, "d": 4}, ["a", "b", "c"])
{'a': 1, 'b': 2, 'c': 3}
"""
python
def prune(d, keys):
"""Return a copy of D which only contains key/value pairs
whose keys are also in KEYS.
>>> prune({"a": 1, "b": 2, "c": 3, "d": 4}, ["a", "b", "c"])
{'a': 1, 'b': 2, 'c': 3}
"""
return {k: d[k] for k in keys}
python
def index(keys, values, match):
"""Return a dictionary from keys k to a list of values v for which
match(k, v) is a true value.
>>> index([7, 9, 11], range(30, 50), lambda k, v: v % k == 0)
{7: [35, 42, 49], 9: [36, 45], 11: [33, 44]}
"""
python
def index(keys, values, match):
"""Return a dictionary from keys k to a list of values v for which
match(k, v) is a true value.
>>> index([7, 9, 11], range(30, 50), lambda k, v: v % k == 0)
{7: [35, 42, 49], 9: [36, 45], 11: [33, 44]}
"""
return {k: [v for v in values if match(k, v)] for k in keys}
Many useful way to combine lists and dicts:
Lists of lists | [ [1, 2], [3, 4] ] |
Dicts of dicts | {"name": "Brazilian Breads", "location": {"lat": 37.8, "lng": -122}} |
Dicts of lists | {"heights": [89, 97], "ages": [6, 8]} |
Lists of dicts | [{"title": "Ponyo", "year": 2009}, {"title": "Totoro", "year": 1993}] |
Slicing a list creates a new list with a subsequence of the original list.
python
letters = ["A", "B", "C", "D", "E", "F"]
# 0 1 2 3 4 5
sublist1 = letters[1:] # ['B', 'C', 'D', 'E', 'F']
sublist2 = letters[1:4] # ['B', 'C', 'D']
Slicing also works for strings.
python
compound_word = "cortaúñas"
word1 = compound_word[:5] # "corta"
word2 = compound_word[5:] # "úñas"
Negatives indices and steps can also be specified.
Slicing a whole list copies a list:
python
listA = [2, 3]
listB = listA
listC = listA[:]
listA[0] = 4
listB[1] = 5
list()
creates a new list containing existing elements from any iterable:
python
listA = [2, 3]
listB = listA
listC = list(listA)
listA[0] = 4
listB[1] = 5
Python3 provides more ways in the copy module.
The following built-in functions work for lists, strings, dicts, and any other iterable data type.
Function | Description |
---|---|
sum(iterable, start) |
Returns the sum of values in iterable , initializing sum to start
|
all(iterable) |
Return True if all elements of iterable are true (or if iterable is empty)
|
any(iterable) |
Return True if any element of iterable is true. Return False if iterable is empty.
|
max(iterable, key=None) |
Return the max value in iterable
|
min(iterable, key=None) |
Return the min value in iterable
|
python
sum([73, 89, 74, 95], 0) # 331
python
all([True, True, True, True]) # True
any([False, False, False, True]) # True
all([x < 5 for x in range(5)]) # True
perfect_square = lambda x: x == round(x ** 0.5) ** 2
any([perfect_square(x) for x in range(50, 60)]) # False
python
max([73, 89, 74, 95]) # 95
max(["C+", "B+", "C", "A"]) # C+
max(range(10)) # 9
A key function can decide how to compare each value:
python
coords = [ [37, -144], [-22, -115], [56, -163] ]
max(coords, key=lambda coord: coord[0]) # [56, -163]
min(coords, key=lambda coord: coord[0]) # [-22, -115]
python
gymnasts = [ ["Brittany", 9.15, 9.4, 9.3, 9.2],
["Lea", 9, 8.8, 9.1, 9.5],
["Maya", 9.2, 8.7, 9.2, 8.8] ]
min(gymnasts, key=lambda scores: min(scores[1:])) # ["Maya", ...]
max(gymnasts, key=lambda scores: sum(scores[1:], 0)) # ["Brittany", ...]
If a recursive function needs to keep track of more state than the arguments of the original function, you may need a helper function.
python
def fUnKyCaSe(text):
"""
>>> fUnKyCaSe("wats up")
'wAtS Up'
"""
def toggle_case(letter, should_up_case):
return letter.upper() if should_up_case else letter.lower()
def up_down(text, should_up_case):
if len(text) == 1:
return toggle_case(text, should_up_case)
else:
return toggle_case(text[0], should_up_case) + \
up_down(text[1:], not should_up_case)
return up_down(text, False)
Let's code this up recursively:
python
def sum_nums(nums):
"""Returns the sum of the numbers in NUMS.
>>> sum_nums([6, 24, 1984])
2014
>>> sum_nums([-32, 0, 32])
0
"""
Docstrings typically would not specify whether an approach was recursive or iterative, since that is an implementation detail.
However, we'll make it clear in assignments and exam questions.
python
def sum_nums(nums):
"""Returns the sum of the numbers in NUMS.
>>> sum_nums([6, 24, 1984])
2014
>>> sum_nums([-32, 0, 32])
0
"""
if nums == []:
return 0
else:
return nums[0] + sum_nums( nums[1:] )
When recursively processing lists, the base case is often the empty list and the recursive case is often all-but-the-first items.
python
def reverse(s):
"""Returns a string with the letters of S
in the inverse order.
>>> reverse('ward')
'draw'
"""
Breaking it down into subproblems:
python
reverse("ward") = reverse("ard") + "w"
reverse("ard") = reverse("rd") + "a"
reverse("rd") = reverse("d") + "r"
reverse("d") = "d"
python
def reverse(s):
"""Returns a string with the letters of S
in the inverse order.
>>> reverse('ward')
'draw'
"""
if len(s) == 1:
return s
else:
return reverse(s[1:]) + s[0]
When recursively processing strings, the base case is typically an empty string or single-character string, and the recursive case is often all-but-the-first characters.
python
def reverse(n):
"""Returns N with the digits reversed.
>>> reverse_digits(123)
321
"""
Data type | Base case condition | Current item | Recursive case argument |
---|---|---|---|
Numbers | == 0 == 1
| n
| n - 1
|
Numbers (Digits) | == 0
< 10
| n % 10
| n // 10
|
Lists | == [] len(L) == 0
| L[0] L[-1]
| L[1:] L[:-1]
|
Strings | == '' len(S) == 1
| S[0]
| S[1:] S[:-1]
|
Lists are represented as a row of index-labeled adjacent boxes, one per element.
python
pair = [1, 2]
Each box either contains a primitive value or points to a compound value.
python
matrix = [ [1, 2, 0, 4], [0, 1, 3, -1], [0, 0, 1, 8] ]
A very nested list:
python
worst_list = [ [1, 2],
[],
[ [3, False, None], [4, lambda: 5]]]
Sea Level Rise, by Douwe Osinga: Visualize sea levels and population density on interactive maps.
Technologies used: Python (notebook) with PIL/numpy/Rasterio, HTML/CSS/JS with PanZoom
(Github repository)