Uploaded by Guillermo Mascaro

Lesson 5. Simple data structures

advertisement
Lesson 5. Simple data structures
October 9, 2021
1
Introduction
• A data structure is no more than a set of data items grouped together into the same variable
–> we reserve multiple memory cells and give them a unique name (a string can be considered
a very simple data structure)
• They allow us to store several data using only one variable
• Two types of simple data structures:
• To store several data of the same type (arrays): in Python we have lists and tuples
• To store some data of different types (records): in Python we have dictionaries
and objects
2
Lists
• Lists are the equivalent to arrays in other languages
• A list is a finite, heterogeneous and mutable collection of elements indexed by position
• finite means that there is a maximum number of elements in a list (it depends on
the computer)
• heterogeneous means that a list may contain data of different types (unlike arrays
in other languages that only allow to store data of the same type)
• mutable means that the elements of the list can be changed. I can add, delete or
modify elements.
• indexed by position: we access to each element by its position in the list (similar
to the way we access letters in a string)
• A string is a finite, homogeneous and inmutable collection of elements (characters) indexed
by position
• Syntax: list_name = [element1, element2, element3]
[1]: # A list of 4 integer elements
list1 = [1, 2, 3, 4]
# A list of 5 heterogeneous elements
list2 = [1, "hello", 3.54, False, 3 + 2j]
# I can use [] to access to the elements of a list, the 1st is at position 0
print("The first element of", list1, "is", list1[0])
print("The 2nd element from the end of", list1, "is", list1[-2])
# There is no problem on changing elements inside a list (lists are mutable)
list1[2] = "hello"
1
print(list1)
print("List is now:", list1)
# Max number of elements of a list depends on the computer. To know it:
import sys
print("Maximum number of elements in a list in this computer:",sys.maxsize)
3
[1, 2, 'hello', 4]
Maximum number of elements in a list in this computer: 9223372036854775807
2.1
Ways to create lists
• Using literals to enumerate the elements of the list, only usefull in small lists
• Using variables to give the values: It copies the value of the variable, there is no relation
between the variable and the list element. If one changes the other one does not
• Using another list and the + operator: A new list is created with the values of the other list.
If one changes the other one does not
• Using * to repeat some parts of the list
• Using loops: quite used in big lists (an alternative is to use list comprehension)
[2]: # Using literals
list1 = [1, 2, 3, 4, 5, 6]
print("list1 is", list1)
# Using variables (the values are copied)
a, b, c = 1, 2, 3
# This is read as copy the values of a, b, c into the list
list2 = [a, b, c]
print("list2 is",list2)
# The value of a is changed
a = 8
# But the value of the corresponding element of the list is not changed
print("list2 is", list2, "it does not change")
# Using other list(s)
list3 = ["hello", "how", 'are', 'you']
list4 = list1 + list2 + list3
print("list4 is", list4)
list1[0] = 0
print("list1 is", list1)
print("list4 is", list4, "it does not change")
# The + operator needs two lists
list1 = list1 + [5]
# beware with strings
list1 += ["hello"]
print(list1)
# If we forget the [] when using + the result is different
list1 += "hello"
print(list1)
# Using *
2
list5 = list1 * 2 + [4, 6]
print("list5 is", list5)
# Using a loop and the + operator
list6 = []
for i in range(10):
list6 += [i]
print("list6 is", list6)
list1 is [1, 2, 3, 4, 5, 6]
list2 is [1, 2, 3]
list2 is [1, 2, 3] it does not change
list4 is [1, 2, 3, 4, 5, 6, 1, 2, 3, 'hello', 'how', 'are', 'you']
list1 is [0, 2, 3, 4, 5, 6]
list4 is [1, 2, 3, 4, 5, 6, 1, 2, 3, 'hello', 'how', 'are', 'you'] it does not
change
[0, 2, 3, 4, 5, 6, 5, 'hello']
[0, 2, 3, 4, 5, 6, 5, 'hello', 'h', 'e', 'l', 'l', 'o']
list5 is [0, 2, 3, 4, 5, 6, 5, 'hello', 'h', 'e', 'l', 'l', 'o', 0, 2, 3, 4, 5,
6, 5, 'hello', 'h', 'e', 'l', 'l', 'o', 4, 6]
list6 is [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
2.2
Functions and operators with lists
• As we have seen, to access an element we use its index (first is zero). Error if we try to access
a non-existing element. If we use negative numbers we start from the end of the list (first is
-1). We can also use + and *.
• We can use slicing operators [a:b] like in strings
• We can use the in and not in operators to check if an element is inside a list or not
• Functions that we can use with lists:
• print(list): prints all the elements of the list
• len(list): returns the number of elements of a list
• del(list[index]): removes the element at position index from the list. If you
want to delete several elements, it is better to start deleting by the last one (if you
delete one, all the remaining ones change their positions). You can use negative
numbers to start deleting from the end
• del(list): removes all the elements of the list, and also the variable (not really
compulsory as python takes care of deleting no longer needed variables)
• del(list[pos1:pos2]): removes the elements between pos1 and pos2 (the last
not included)
[3]: print("list1 is", list1)
# Print elements 0 and 1
print("elements 0 and 1 of list1", list1[0:2])
# Unlike in strings (which are inmutable) we can use slicing operators to change
# parts of a list
# Changing elements 0 and 1 by [9]. You change a sublist by another sublist
list1[0:2] = [9]
3
print("list1 is", list1)
# To see the length of a list
print("list4 is", list4, "and has length", len(list4))
# This removes element 2
del(list4[2])
print("Removed element #2 of list4", list4)
# This removes 0 and 1
del(list4[0:2])
print("Now removing 0 and 1", list4)
# An alternative way is to do list4[0:2] = []
# This says if 5 is an element of list4 (is element in list?)
print("Is there a 5 in list4?", 5 in list4)
list1 is [0, 2, 3, 4, 5, 6, 5, 'hello', 'h', 'e', 'l', 'l', 'o']
elements 0 and 1 of list1 [0, 2]
list1 is [9, 3, 4, 5, 6, 5, 'hello', 'h', 'e', 'l', 'l', 'o']
list4 is [1, 2, 3, 4, 5, 6, 1, 2, 3, 'hello', 'how', 'are', 'you'] and has
length 13
Removed element #2 of list4 [1, 2, 4, 5, 6, 1, 2, 3, 'hello', 'how', 'are',
'you']
Now removing 0 and 1 [4, 5, 6, 1, 2, 3, 'hello', 'how', 'are', 'you']
Is there a 5 in list4? True
2.3
List methods
List methods allow us to work with lists. They are like functions that we can apply only to a list.
The way to apply them is to put list_name.method() (functions are function(list_name)). We
ask the list to execute that method.
• append(element): adds an element at the end of the list. It is much more efficient to use
list_name.append(element) than list_name = list_name + [element]
• insert(index, element): inserts the element at the given position. If the position does not
exist it will append it at the end. If you use a negative index, it will start counting from the
end: insert(-1, element) is equivalent to append(element)
• list1.extend(list2): appends all the elements of list2 to list1. Equivalent to list1
= list1 + list2 but using the + sign is less efficient as a copy of both lists is created and
assigned to list1
• index(element): returns the position of the element in the list. Error if the list does not
contain the element (I should check first the element is in the list). If the element is repeated
it returns the first position
• index(element, start, end): returns the position of the element in the sublist between
start and end (not included). end is optional.
• count(element): returns the number of times the element is in list
• clear(): removes all the elements of the list. The list will be the empty one. With the
del(list) function you also remove the variable, here the variable exists
• remove(element): deletes the first appearance of the element in the list. If the element does
not belong to the list, error. With del(list([index]), we remove giving the position, here
we give the element
4
• pop(): removes and returns the last element. The element should be stored in another
variable.
• pop(index): removes and returns the element at a given position. The element should be
stored in another variable.
• reverse(): reverses the list
• sort(): sorts the list. It only works for lists made of similar elements (you cannot sort a list
containing both string and numbers)
[4]: list1 = [1, 2, 3, 4, 5]
# Adding a new element
list1.append(0)
print("list1 is", list1)
# An alternative way is to use + and to include the element into its own list
# It is better to use append (it is faster)
list1 = list1 + [3]
print("list1 is", list1)
# beware with strings
list1 += ["bye"]
print("list1 is", list1)
# if we don't enclose the string in a list it considers each element in␣
,→isolation
list1 += "bye"
print("list1 is", list1)
# Inserts "hello" at the second position of the list
list1.insert(2, "hello")
print("list1 is", list1)
# Append one list to another one with extend
# It copies one by one the elements of list2 into list1
list2 = [2.2, "Pepe"]
list1.extend(list2)
print("list1 is", list1)
# Notice that if we append one list to the other, the second is appended
# as a single element. Now, the last element of list1 is also a list
list1.append(list2)
print("list1 is", list1)
# Which is the index of 3 in list1?
print("First 3 in list 1 is at position", list1.index(3))
# Which is the index of 3 between positions 4 and 8 (in the sublist from 4 to␣
,→8)?
print("There is a 3 at position", list1.index(3, 4, 8), "between elements 4 and␣
,→8")
# If you want to know the types of the elements of a list
print("The type of the 6th element of the list is", type(list1[6]))
# How many times 3 is in list?
print("There are", list1.count(3), "3's in the list")
# Removes the first 3 in list3
list1.remove(3)
5
print("list 1 is", list1)
# Removing all the elements of list1,
list1.clear()
print("list 1 is", list1)
list1 is [1, 2, 3, 4, 5, 0]
list1 is [1, 2, 3, 4, 5, 0, 3]
list1 is [1, 2, 3, 4, 5, 0, 3, 'bye']
list1 is [1, 2, 3, 4, 5, 0, 3, 'bye', 'b', 'y', 'e']
list1 is [1, 2, 'hello', 3, 4, 5, 0, 3, 'bye', 'b', 'y', 'e']
list1 is [1, 2, 'hello', 3, 4, 5, 0, 3, 'bye', 'b', 'y', 'e', 2.2, 'Pepe']
list1 is [1, 2, 'hello', 3, 4, 5, 0, 3, 'bye', 'b', 'y', 'e', 2.2, 'Pepe', [2.2,
'Pepe']]
First 3 in list 1 is at position 3
There is a 3 at position 7 between elements 4 and 8
The type of the 6th element of the list is <class 'int'>
There are 2 3's in the list
list 1 is [1, 2, 'hello', 4, 5, 0, 3, 'bye', 'b', 'y', 'e', 2.2, 'Pepe', [2.2,
'Pepe']]
list 1 is []
[5]: # Using reverse and sort
list1 = [1, 2, 3, 4, 5]
list1.reverse()
print("list1 is", list1)
# Pop removes and returns the last element of the list (with remove the element␣
,→is
# just thrown away)
a = list1.pop()
print("The variable a, now contains the last element of the list:", a)
print("list1 is", list1)
# sort the list in order (the elements must be compatible)
list2 = [1, 2, 3.1, 0.2, 5, 3]
list2.sort()
print("list2 is", list2)
list1 is [5, 4, 3, 2, 1]
The variable a, now contains the last element of the list: 1
list1 is [5, 4, 3, 2]
list2 is [0.2, 1, 2, 3, 3.1, 5]
2.4
Comparing lists
• We can use == and != to see if two lists are equal or not (they are equal only if they have the
same elements in the same order)
• We can also use < <= > >=
6
• They compare element by element (first to first, second to second and so on) If both lists are
equal then they compare the length
[8]: list1 = [1, 2, 3, 4]
list2 = [1, 2, 3, 4]
list3 = [1, 1, 3, 4, 5, 6, 7]
list4 = [1, 2, 3, 4, 5]
print("are", list1, "and", list2, "equal?", list1 == list2)
# list3 is smaller than list1, because the first different element of list3 is␣
,→smaller
# (the '1' at position number 1)
print("is", list3, "less than", list1, "?", list3 < list1)
# We can compare lists of heterogeneous elements, given that elements at
# similar positions are comparable
list5 = [1, "hello", True]
list6 = [1, "bye", False]
# list 5 is not smaller because the elements 1 start by 'h' and 'b' and 'h'>'b'
print("is", list5, "less than", list6, "?", list5 < list6)
# list4 > list1 as all the common elemnts are equal but list4 is bigger
print("is", list4, "greater than", list1, "?", list4 > list1)
# But length is only considered when all the elements are equal
# position 1 of list4 is greater than positon1 of list3
print("is", list4, "greater than", list3, "?", list4 > list3)
are [1, 2, 3, 4] and [1, 2, 3, 4] equal? True
is [1, 1, 3, 4, 5, 6, 7] less than [1, 2, 3, 4] ? True
is [1, 'hello', True] less than [1, 'bye', False] ? False
is [1, 2, 3, 4, 5] greater than [1, 2, 3, 4] ? True
is [1, 2, 3, 4, 5] greater than [1, 1, 3, 4, 5, 6, 7] ? True
2.5
Copying lists
• If you assign a list to another list using = they are actually the same list (don’t do it). They
behave like this because they are mutable. We can check it using the id() function or the is
operator
• The is operator tells me if two variables point to the same memory address (identity operator)
• Proper ways to copy lists:
•
•
•
•
Using
Using
Using
Using
loops
slicing
the .copy() method
.extends() method on an empty list
[9]: list1 = [1, 2, 3, 4]
# list1 and list2 are the same list, they point to the same memory address. Is␣
,→like
# having a list with two names
list2 = list1
7
list2[0] = "hello"
print("list 1 is", list1)
# We can use the id() function to check that actually they are the same list
print("id of list1", id(list1))
print("id of list2", id(list2))
print("Are list1 and list2 the same list?", list1 is list2)
list3 = ["hello", 2, 3, 4]
# list1 and list3 are equal
print("Are list1 and list3 equal?", list3 == list1)
# but they are not the same list (they are at different memory positions)
print("Are list1 and list3 the same list?", list3 is list1)
# Copying list1 into list2 using loops
# We create an empty list and then use a for loop to append elements to it
list2 = []
for element in list1:
list2.append(element)
print("Copying with a loop")
print("list2 is", list2)
print("Are list1 and list2 the same list?", list2 is list1)
print("id of list1", id(list1))
print("id of list2", id(list2))
# Copying list1 into list2 using slicing
list2 = list1[:]
print("Copying with slicing")
print("list2 is", list2)
print("Are list1 and list2 the same list?", list2 is list1)
print("id of list1", id(list1))
print("id of list2", id(list2))
# Using the copy method (if list2 had any values they are lost)
list2 = list1.copy()
print("Copying with copy() method")
print("list2 is", list2)
print("Are list1 and list2 the same list?", list2 is list1)
print("id of list1", id(list1))
print("id of list2", id(list2))
# Using extends (the list2 must be empty)
list2 = []
list2.extend(list1)
print("Copying with extends")
print("list2 is", list2)
print("Are list1 and list2 the same list?", list2 is list1)
print("id of list1", id(list1))
print("id of list2", id(list2))
list 1 is ['hello', 2, 3, 4]
id of list1 15282120
8
id of list2 15282120
Are list1 and list2 the same list?
Are list1 and list3 equal? True
Are list1 and list3 the same list?
Copying with a loop
list2 is ['hello', 2, 3, 4]
Are list1 and list2 the same list?
id of list1 15282120
id of list2 80386632
Copying with slicing
list2 is ['hello', 2, 3, 4]
Are list1 and list2 the same list?
id of list1 15282120
id of list2 80414856
Copying with copy() method
list2 is ['hello', 2, 3, 4]
Are list1 and list2 the same list?
id of list1 15282120
id of list2 15278184
Copying with extends
list2 is ['hello', 2, 3, 4]
Are list1 and list2 the same list?
id of list1 15282120
id of list2 80414280
2.6
True
False
False
False
False
False
Lists and loops
We use loops to work with lists. The most suitable loop depends on whether you want to change
the value of some elements of the list, and if you plan to walk through the entire list or not
• If I want to walk through the entire list and I don’t want to change any of its values: for-each
loop
• If I want to walk through the entire list and I want to change any of its values: for-range loop
• If don’t want to walk through the entire list: while
[8]: # First example: for each
# Adds the elements of the list
# We want to walk through the entire list but no changes on it
list1 = [1, 2, 3, 4, 5, 6]
result = 0
for element in list1:
# Each iteration one element of my list is copied into the
# element variable, and I work with the copy
result = result + element
print(result)
# Second example: for range
# Changes elements with odd value to even value
9
# We want to walk through the entire list and perform some changes
for index in range(len(list1)):
if list1[index] % 2 != 0:
list1[index] += 1
print(list1)
# Third example: for range also to create the list
# Filling a list with 10 random numbers
import random
list3 = []
for index in range(10):
list3.append(random.randrange(0,100))
print(list3)
# Third example: while
# We don't know if we need to walk through all the list
# Use it both if you want to make changes or not
index = 0
found = False
while not found and index < len(list1):
if list1[index] > 3:
found = True
else:
index = index + 1
if found:
print("The element at position", index, "is greater than 3")
else:
print("No element is greater than 3")
21
[2, 2, 4, 4, 6, 6]
[47, 57, 55, 65, 82, 59, 35, 26, 94, 1]
The element at position 2 is greater than 3
3
Tuples
• A finite, immutable sequence of heterogeneous elements indexed by position
• Elements of a tuple can not be changed, neither the length of the tuple
• variable = (element1, element2, element3 ...)
• Parentheses are optional
• Ways to create tuples:
• Using literals
• Using variables: values of the variables are copied to the tuple. If the variable
changes, the tuple does not
10
•
•
•
•
Using
Using
Using
Using
the + operator and another tuple(s). Values of the tuples are copied
the * operator and another tuple
a list and casting it to tuple with tuple(list)
tuple comprehension (we will not see it)
• We can extend a tuple by assigning itself plus the extension, but this is a new tuple (see ids).
This is very inefficient in time
[13]: # Creating tuples with literals
tup = (1, 2, 3, 4, 5)
# Parentheses are optional
tup2 = "hello", 2, "bye", True, 2.2
# A single element tuple needs a comma at the end
tup3 = (1,)
# This is not a tuple but a integer 1 is stored
not_a_tuple = (1)
print("tup is", tup)
print("tup2 is",tup2)
print("tup3 is",tup3)
print("this is not a tuple", not_a_tuple)
print("the first element of tup3 is",tup3[0])
# Creating tuples with variables
a, b, c = 2, 5, "hello"
tup4 = (a, b, c)
print("tup4 is", tup4)
a = 12
print("The new value of a is", a)
print("tup4 is ", tup4, "no changes")
# Using the + operator
tup5 = tup + tup2
print("tup5 is", tup5)
# Using the * operator
tup6 = 2 * tup + 3 * tup3
print("tup6 is", tup6)
# Using a list and casting it
list1 = [1, 2, 3, 4, 5, 6]
tup7 = tuple(list1)
print("tup7 is", tup7)
print("list1 is", list1)
list1[0] = 8
print("list1 is", list1, "it changes")
print("tup7 is", tup7, "no changes")
# We can extend a tuple by assigning itself plus the extension,
# but this is a new tuple (see ids). This is very inefficient in time
tup8 = (1, 2, 3)
print("The id of tup8 is", id(tup8))
tup8 = tup8 + (5, 6, 7)
print("Now the id is", id(tup8))
11
print("tup8 is", tup8)
# I cannot change the value of an element, this raises an error
# tup8[0] = 7
# This is no longer a tuple, don't do it
tup8 = "hello"
tup is (1, 2, 3, 4, 5)
tup2 is ('hello', 2, 'bye', True, 2.2)
tup3 is (1,)
this is not a tuple 1
the first element of tup3 is 1
tup4 is (2, 5, 'hello')
The new value of a is 12
tup4 is (2, 5, 'hello') no changes
tup5 is (1, 2, 3, 4, 5, 'hello', 2, 'bye', True, 2.2)
tup6 is (1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 1, 1)
tup7 is (1, 2, 3, 4, 5, 6)
list1 is [1, 2, 3, 4, 5, 6]
list1 is [8, 2, 3, 4, 5, 6] it changes
tup7 is (1, 2, 3, 4, 5, 6) no changes
The id of tup8 is 98162184
Now the id is 97992248
tup8 is (1, 2, 3, 5, 6, 7)
3.1
Why do we use tuples?
• We want to have something like a constant containing several values. We mark that the
program shouldn’t change it (it is relevant when we are working with functions)
• Sometimes Python is forcing us to use tuples (because it needs something immutable)
• Using tuples is faster? and requires less memory
[10]: tup1 = (1, 2, 3)
print("tup1 is", tup1)
print("its memory address is", id(tup1))
# This is a totally different variable, I am reusing the name
tup1 = (3, 2, 4, 5, 6)
print("tup1 is", tup1)
print("its memory address is", id(tup1), "it changed, it is another variable")
# I am reusing the name (don't do that!!)
tup1 = "hello"
print("now tup 1 is", tup1, ": it is a string, not a tuple anymore")
print("its memory address is", id(tup1), "it changed again")
# Sometimes you can see things like this
# It may seem a way to extend a tuple, but actually you are creating a new one
# Doing it is quite inefficient
tup1 = (1, 2, 3)
print("tup1 is", tup1)
print("its memory address is", id(tup1))
12
tup1 += (4, 5)
print("tup1 is", tup1)
print("its memory address is", id(tup1), "it changed, it is another variable")
tup1 is (1, 2, 3)
its memory address is 91722736
tup1 is (3, 2, 4, 5, 6)
its memory address is 91913360 it changed, it is another variable
now tup 1 is hello : it is a string, not a tuple anymore
its memory address is 94361952 it changed again
tup1 is (1, 2, 3)
its memory address is 91714064
tup1 is (1, 2, 3, 4, 5)
its memory address is 91913360 it changed, it is another variable
3.2
Operators, functions and methods with tuples
•
•
•
•
•
•
•
•
id(tuple): returns the id (memory address) of the tuple
type(tuple)
del(tuple): erases the tuple and the variable
len(tuple): returns the length
print(tuple): prints it
element in tuple: true if the element belongs to the tuple
Slicing to get elements, not to change them (like in strings)
.index(x): returns the index of the first element in tuple whose value is x. Error if x does
not exist
• .index(x, start, end): returns the index of the first element in the subtuple [start,
end) whose value is x. Error if x does not exist
• .count(x): returns the number of occurrences of x in tuple
[14]: print("Is there a 3 in tup?", 3 in tup)
print("How many 3's in tup?", tup.count(3))
print("The position of the first 3 in the tuple is", tup.index(3))
Is there a 3 in tup? True
How many 3's in tup? 1
The position of the first 3 in the tuple is 2
3.3
Packing and unpacking
• Packing means creating a tuple/list using some variables
• Unpacking means copying each element of a tuple/list into a variable (as many variables as
tuple/list elements are needed)
[15]: # This is packing
a, b, c, d = 1, 4, 6, 1
list1 = [a, b, c, d]
tup1 = (a, b, c, d)
13
# Unpacking (every element of the tuple/list is copied into a variable)
# I need to have as many variables as tuple/list elements
var1, var2, var3, var4 = tup1
print("var1 is", var1)
print("var2 is", var2)
print("var3 is", var3)
print("var4 is", var4)
# The type of each one is different
print(type(tup1))
print(type(var3))
var1 is 1
var2 is 4
var3 is 6
var4 is 1
<class 'tuple'>
<class 'int'>
4
Casting with lists and tuples
• list(collection): converts that collection into a list
• tuple(collection): converts that collection into a tuple
Usually we work with lists, and once we are sure we don’t want to change them them anymore we
cast them to tuples
We can also convert a String to a tuple/list or use the range function to create tuples/lists But we
cannot use this casting for a number or boolean. Only collections can be converted
[13]: # Casting tuple to list and viceversa
list1 = list(tup1)
tuple1 = tuple([1,2,3])
print(list1)
print(tuple1)
# Creating a list using range
auto_list = list(range(1,11))
print(auto_list)
# Not really useful...
st = tuple('hello')
print(st)
[1, 4, 6, 1]
(1, 2, 3)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
('h', 'e', 'l', 'l', 'o')
14
5
Nested lists and tuples
• A list/tuple inside a list/tuple (matrixes in other languages). A list/tuple whose elements are
also lists/tuples
[16]: # This is a nested list
mat = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(mat)
# The first element is also a list (it can be seen as a row in a matrix)
print(mat[0])
# Element at column 1 in row 1
print(mat[1][1])
# Changing an element of a sublist
mat[1][2] = 33
print(mat)
# Appending an element to a sublist
mat[1].append(12)
print(mat)
# Appending an element to the list
mat.append(12)
print(mat)
# Some operations with nested lists
# Methods and operators only work with 1st level items, they don't
# go inside the sublists
print("The length of the list is", len(mat))
print("Is there a 1 in the list?", 1 in mat)
print("How many 3's are there?", mat.count(3))
print("Is there a 12 in the list?", 12 in mat)
# To count the number of 12's I need to use loops
number = 0
# For each element of the list
for row in mat:
# If the element is a list
if type(row) == list:
# I use count, as it is a list
number = number + row.count(12)
else:
# If it is not a list, I assume it is a literal
# but it may be also a tuple or other not seen yet
# data structure like dictionaries or objects.
if row == 12:
number = number + 1
print("The number of 12's inside the matrix is", number)
# I add a sublist inside a sublist
mat[2].append([1, 2, 3])
print(mat)
# To access one of its elements I need 3 indexes
15
mat[2][3][1] = "hello"
print(mat)
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[1, 2, 3]
5
[[1, 2, 3], [4, 5, 33], [7, 8, 9]]
[[1, 2, 3], [4, 5, 33, 12], [7, 8, 9]]
[[1, 2, 3], [4, 5, 33, 12], [7, 8, 9], 12]
The length of the list is 4
Is there a 1 in the list? False
How many 3's are there? 0
Is there a 12 in the list? True
The number of 12's inside the matrix is 2
[[1, 2, 3], [4, 5, 33, 12], [7, 8, 9, [1, 2, 3]], 12]
[[1, 2, 3], [4, 5, 33, 12], [7, 8, 9, [1, 'hello', 3]], 12]
5.1
Copying nested lists
• You cannot use =
• If you use loops, copy() or slicing you will perform what is called shallow copy. The two lists
will be different but their elements will be the same
• When working with nested lists you need to use deep copy. Two ways:
• Use the copy library: import copy a = copy.deepcopy(b) not to be used this
year
• Use a nested loop
[15]: mat1 = [[1, 2], [3, 4]]
mat2 = mat1.copy()
print(mat2)
print("Are mat1 and mat2 the same matrix?", mat2 is mat1)
mat1[0][0] = 12
# If I change one elment of mat1, the same element of mat2 changes
# lists are different but elements are pointing to the same address
print(mat2, "it has changed!")
print("Are the first elements of mat1 and mat2 the same?", mat1[0] is mat2[0])
# We can use the id's to check it
print("The id of mat1 is", id(mat1))
print("The id of mat2 is", id(mat2))
print("The id of the first element of mat1 is", id(mat1[0]))
print("The id of the first element of mat2 is", id(mat2[0]), "they are equal!")
# Copying with copy is like doing mat2[0] = mat1[0]
#, mat2[1] = mat1[1] and so on. So mat2[x] and mat1[x] will point
# to the same position and will be the same list
# The same happens with slicing
# And also with a for loop
mat2 = []
16
for element in mat1:
mat2.append(element)
mat2[0][0] = "changes in both"
print("mat1 is", mat1)
# Summary: don't use the ways to copy we saw when you have nested lists
#(this is called shallow copy in contrast to what is called deep copy)
# You can use (not this year) the copy library and the deepcopy() method
# or copy with nested loops
#Notice that only common elements are the same, if we add a new element in
# the other does not change
mat1.append(12)
print("mat1 is", mat1)
print("mat2 is", mat2, "no element added!")
# But if we change one of the sublists in any way, the other list changes
mat1[0].append(33)
print("mat1 is", mat1)
print("mat2 is", mat2)
mat2[1].append(133)
print("mat1 is", mat1)
print("mat2 is", mat2)
# Nested loop to deep copy
# It only works if sublists do not contain lists
# We'll see a technique in next lesson to perform deep copy to any level
mat2 = []
for item in mat1:
# If it is not a list, we append it
if not type(item) == list:
mat2.append(item)
else:
# If it is a list, we append an empty list
mat2.append([])
# And copy the sublist (-1 is the last element of mat2)
mat2[-1] = item.copy()
# Now they are not related anymore
print("mat1 is", mat1)
print("mat2 is", mat2)
mat2[0][0] = "no changes"
print("mat1 is", mat1)
print("mat2 is", mat2)
[[1, 2], [3, 4]]
Are mat1 and mat2 the same matrix? False
[[12, 2], [3, 4]] it has changed!
Are the first elements of mat1 and mat2 the same? True
The id of mat1 is 94408176
17
one
The id of mat2 is 94408056
The id of the first element of mat1 is 94408096
The id of the first element of mat2 is 94408096 they are equal!
mat1 is [['changes in both', 2], [3, 4]]
mat1 is [['changes in both', 2], [3, 4], 12]
mat2 is [['changes in both', 2], [3, 4]] no element added!
mat1 is [['changes in both', 2, 33], [3, 4], 12]
mat2 is [['changes in both', 2, 33], [3, 4]]
mat1 is [['changes in both', 2, 33], [3, 4, 133], 12]
mat2 is [['changes in both', 2, 33], [3, 4, 133]]
mat1 is [['changes in both', 2, 33], [3, 4, 133], 12]
mat2 is [['changes in both', 2, 33], [3, 4, 133], 12]
mat1 is [['changes in both', 2, 33], [3, 4, 133], 12]
mat2 is [['no changes', 2, 33], [3, 4, 133], 12]
6
Tuples of lists
• A tuple that contains a list
• As the tuple contains the pointers to the lists and not the lists themselves, we can make
changes on the lists, but we cannot remove or add any list to the tuple.
[1]: # This is a tuple of lists
tup1 = ([1, 2, 3], ["hello", 3, 2.4])
print("the id is", id(tup1))
print("tup1 is", tup1)
print("The length of tup1 is", len(tup1))
# Can we change the contents of one the lists?
tup1[0].append(4)
print("tup1 is", tup1)
print("the id is", id(tup1), "it is still the same tuple")
# We can even clear one of the lists, but we cannot completely
# delete it
tup1[0].clear()
print("tup1 is", tup1)
print("the id is", id(tup1), "it is still the same tuple")
the id is 72016200
tup1 is ([1, 2, 3], ['hello', 3, 2.4])
The length of tup1 is 2
tup1 is ([1, 2, 3, 4], ['hello', 3, 2.4])
the id is 72016200 it is still the same tuple
tup1 is ([], ['hello', 3, 2.4])
the id is 72016200 it is still the same tuple
7
Dictionaries
• Finite, mutable and heterogeneous collection of elements indexed by key (a name)
18
•
•
•
•
•
•
•
•
Difference with a list: elements are not ordered, no notion of order in a dictionary
dic = {key1: value1, key2: value2, key3: value3}
A dictionary contains pairs of key and value
Similar to records in other languages, they are also known as hash tables, associative arrays,
maps, or symbol tables
Keys are usually strings but can they can belong to any immutable type (for example tuples,
numbers, etc.)
Values can be literals, but also lists, dictionaries, tuples… (you can have nested dictionaries)
Keys must be unique, if you create two keys with the same name, the second will erase the
first
To create a new key you only need to give a value to it: dic[new_key] = value
[17]: # This is a dictionary, all the keys are str
dic1 = {"name": "Pepe", "age": 18, "surname": "Perez"}
# But we can have also other types of keys (inmutable)
dic2 = {"name": "Pepe", "age": 18, "surname": "Perez", 18: True}
# To access an element we use the key
# Notice that if the key doesn't exist an error is raised (similar
# to trying to access a non-existing index in a list or tuple)
print("The value of the 'name' key is", dic1["name"])
# To change the value of an element, we use the key again
dic1["surname"] = "Gonzalez"
print("dic1 is", dic1)
# If we create two equal keys, the second erases the first
dic3 = {"name": "Pepe", "age": 18, "surname": "Perez", "age": 20}
print("dic3 is", dic3)
# Adding a new key
dic3["address"]= "Leganés and Colmenarejo"
print("dic3 is", dic3, "a new key has been added")
# This creates an empty dictionary
dic4 = {}
print("dic4 is", dic4)
The value of the 'name' key is Pepe
dic1 is {'name': 'Pepe', 'age': 18, 'surname': 'Gonzalez'}
dic3 is {'name': 'Pepe', 'age': 20, 'surname': 'Perez'}
dic3 is {'name': 'Pepe', 'age': 20, 'surname': 'Perez', 'address': 'Leganés and
Colmenarejo'} a new key has been added
dic4 is {}
7.1
•
•
•
•
•
•
Operations, functions and methods with dictionaries
To delete a key: del(dic[key])
in operator: to know if a dictionary contains a key
print(dict): prints the dictionary
len(dict): returns the number of keys
del(dict): erases the dictionary and the variable too
We cannot copy dictionaries using = (same problem as with lists), we cannot use the + to join
19
•
•
•
•
•
•
•
•
two dictionaries
.copy(): creates a copy of this dictionary (shallow copy)
dict1.update(dict2): joins dict1 and dict2 (if any key is repeated it takes the dict2
value)
.clear(): erases both keys and values, but keeps the variable
.get(key): returns the value of that key, and None if the key is not in the dictionary
.values(): returns a list-like with all the values (must be casted to list)
.keys(): returns a list-like with all the keys (must be casted to list)
.items(): returns list-like with tuples containing keys and values (must be casted to
list/tuple)
.pop(key): returns the value of that key and removes the key
[4]: dic4 = {"name": "Pepe", "age": 18, "surname": "Perez", "key": 20}
# Delete a key
del(dic4["name"])
print("dic4 is", dic4)
print("Does dic4 have the key 'age'?", "age" in dic4)
dic5 = dic4.copy()
print("dic5 is", dic5, "a copy of dic4")
dic6 = {"key1": 11, "key2": True, "key": "common key in both"}
dic5.update(dic6)
print("dic5 is extended with dic6:", dic5)
# Erasing a dictionary
dic6.clear()
print("dic6 is", dic6)
# To get the value of a key
# First way: if the key is not existing, you will have an error
#print(dic5["name"])
# Recommended way: no error if the key is not existing
print("The value of the 'name' key of dic5 is", dic5.get("name"))
# To get all the values of the dictionary in a list
vals = list(dic5.values())
print("Values of dic5:", vals)
# To get all the keys
keys = list(dic5.keys())
print("Keys of dic5:", keys)
# To get both values and keys
val_keys = dic5.items()
print("Values and keys of dic5:", tuple(val_keys))
# To get the value of a key and remove it
val = dic5.pop('surname')
print("dic5 is", dic5)
print("the value of the 'surname' key was", val)
print("Result of .items() with no casting to list", val_keys)
dic4 is {'age': 18, 'surname': 'Perez', 'key': 20}
Does dic4 have the key 'age'? True
dic5 is {'age': 18, 'surname': 'Perez', 'key': 20} a copy of dic4
20
dic5 is extended with dic6: {'age': 18, 'surname': 'Perez', 'key': 'common key
in both', 'key1': 11, 'key2': True}
dic6 is {}
The value of the 'name' key of dic5 is None
Values of dic5: [18, 'Perez', 'common key in both', 11, True]
Keys of dic5: ['age', 'surname', 'key', 'key1', 'key2']
Values and keys of dic5: (('age', 18), ('surname', 'Perez'), ('key', 'common key
in both'), ('key1', 11), ('key2', True))
dic5 is {'age': 18, 'key': 'common key in both', 'key1': 11, 'key2': True}
the value of the 'surname' key was Perez
Result of .values() with no casting to list dict_items([('age', 18), ('key',
'common key in both'), ('key1', 11), ('key2', True)])
21
Download