M = [[1, 2], [3, 4]]
You can access the emelents with multiple bracket [ ]
indexing:
M[0][1]
M = [[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[0, 9], [0, 0]]] # 3x2x2 array
M[2][0][1]
Exercise: Write a function that prints a 2D array in a tabular like format:
1 2
3 4
def array_print(M):
for i in range(len(M)):
for j in range(len(M[i])):
print(M[i][j], end='\t') # TAB character
print()
array_print([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
array_print([[1, 2, 3, 3.5], [4, 5, 6, 6.5], [7, 8, 9, 9.5]])
Exercise: Let's say that a store would like to set up a discount system for regular customers. The store's database has the name of the customers (a unique string) and their shopping costs so far. The customers are stored in a list, every element of the list is a pairs: their name and their list of shopping costs. For example one customer entry would look like this:
["Anna", [54, 23, 12, 56, 12, 71]]
The discounts are calculated in the following way:
Total shoppings > 200: $10\%$
Total shoppings > 500: $15\%$
Total shoppings > 1000: $20\%$
Otherwise no discount ($0\%$).
Write a function that calculates the discount for every customer.
["Anna", 10]
How to begin? Break down to subtasks!
228 -> 10
)There are two ways to achive this (design pattern):
# top-down
def discount(customers):
result = []
for customer in customers:
result.append(calculate_discount(customer))
return result
def calculate_discount(customer):
name = customer[0]
total_cost = 0
for shopping in customer[1]:
total_cost += shopping
return [name, discount_from_total(total_cost)]
def discount_from_total(total):
if total > 1000:
return 20
if total > 500:
return 15
if total > 200:
return 10
return 0
discount([["Anna", [54, 23, 12, 56, 12, 71]],
["Bill", [11, 3, 12, 1, 12, 55]],
["Hagrid", [111, 545, 343, 56, 12, 66]],
["Not_a_wizard", [54, 222, 65, 56, 43, 71]]])
We have already seen strings and lists which are similar to the tuple.
An n-tuple can be created with a comma separeted list in a parenthesis or with the tuple()
function:
t = (1, 5, 6, 2, 1)
print(t[2])
type(t)
l = [1, 2, 3]
t = tuple(l)
print(t)
Use for
loop as before:
for e in t:
print(e, end=" ")
But you cannot assign individual elements (like the string)
t[1] = 4
Parenthesis is also used for grouping operations (like in $2\times(3+4)$), but that is different from the parenthesis of the tuple. Also in some cases you don't have to write the parenthesis at all.
x = 2, 3, 4
print(x)
x, y = 2, 3
print(x)
print(y)
1-tuples are different than a single object in a parenthesis, you can construct a 1-tuple with an ending comma inside a parenthesis.
print(type((1)))
print(type((1,)))
The tuple is almost identical to the list except that it is immutable: you cannot assign a single element. The list is mutable.
You cannot change a tuple once created, except creating a new one, like in case of strings:
s = ("h", "e", "l", "l", "o")
print(s[2])
s = ("h", "a", "l", "l", "o")
string = "puppy"
string2 = string[:2] + "ff" + string[4:]
print(string2)
for e in s:
print(e, end=' ')
s[1] = "e"
A dictionary is a series of pairs, we call them key-value pairs. A dictionary can have any type of key and any type of value, but the key have to be immutable.
You can contruct dictionaries with a curly bracket { }
or with the dict()
function.
d = {"puppy": 5}
type(d)
You can add a pair to the dictionary by assigning the value to the bracketed key.
d = {} # empty dictionary
d["cat"] = [1, 5] # add a new key-value pair
d["puppy"] = 3
d
You can access the elements by their keys in a bracket.
d["cat"]
You can use different type of keys (as long as they are immutable):
d = dict()
d[5] = 7
d[(1, 5)] = "puppy"
d[(1, 5)] = "snake"
d["cat"] = 3.14
print(d)
A for
loop iterates over the keys:
for key in d:
print(key, ":", d[key])
customers = {"Anna": [54, 23, 12, 130],
"Bill": [11, 3, 12, 1, 12, 55],
"Hagrid": [111, 545, 343, 56, 12, 66],
"Not_a_wizard": [54, 222, 165, 56]}
print(customers)
print()
print(customers["Bill"])
Exercise: Write a program, which save the discount for every costumers! Rewrite the previous one!
def discount(customers):
for customer in customers:
customers[customer] = {"shl": customers[customer]}
customers[customer]["d"] = calculate_disc(customers[customer]["shl"])
print(customer, customers[customer]["d"])
def calculate_disc(shl):
total_cost = 0
for shopping in shl:
total_cost += shopping
return discount_from_total(total_cost)
def discount_from_total(total):
if total > 1000:
return 20
if total > 500:
return 15
if total > 200:
return 10
return 0
discount(customers)
customers.keys()
customers.values()
for i in customers.values():
print(i)
The dictionary uses a so-called hash function to calculate where to put the elements. In this way it it can find every key-value quickly.
You can observe the hash values yourself with the hash()
function:
print(hash((1, 5)))
print(hash(5), hash(0), hash(False), hash(True))
print(hash((5,)))
print(hash("puppy"))
print(hash("puppz"))
print(hash("muppy"))
print(hash("puppy, cat, python, galahad ..."))
The dictionary uses the hash function, but a similar function is common in both theoretical and applied computer science. There are advanced algorithm courses about hash functions.
The hash() functions are important in other areas of computer science Advances Datastructures and Techniques for Analysis of Algorithms, Katalin Friedl, Gyula Katona.
What is a hash function:
There may be extra requirements in other applications (cryptographic hash function):
dict
)A data type is iterable if it can be iterated over with a for
loop.
Example:
for x in <iterable>:
<do stuff>
There are some useful functions that can be used on any iterables:
# repetition
print("puppy "*3)
print((1, 2, 3)*3)
print([1, 2, 3]*3)
# concatenation (except for dict)
(1, 2) + (2, 4, 6)
# universal (boolean and)
print(all((False, True, True, True)))
print(all((0, 1, 1, 1)))
# existential (boolean or)
any((0, 1, 1, 1))
# "transpose"
zip([1, 2, 3], [11, 12, 13])
list(_)
array_print(_) # use our previously written function
# sum (for numbers, not for strings)
sum((1, 2, 3))