310 KiB
Session 2¶
Use a locally installed editor like Visual Studio Code or this online editor: https://www.onlinegdb.com/online_python_compiler
Data Structures¶
Data structures are constructs that can contain one or more variables.
There are four basic data structures in Python:
- Lists
- Dictionaries
- Tuples
- Sets
Lists¶
Lists are defined by sqaure brackets [] with elements separated by commas. They can have elements of any data type.
Lists are probably the most used data structure.
Mutability¶
Lists are mutable. They can be changed after creation.
List examples¶
Some examples of lists:
a = [10, 20, 30, 40]
b = [1, True, 'Hi!', 4.3] # Multiple data types in the same list
c = [['Nested', 'lists'], ['are', 'possible']] # List of lists
Dictionaries¶
Dictionaries have key/value pairs. This can for some problems be easier than having two lists that relate to eachother by index.
Syntax : {key1: value1, key2: value2, ..., key_n, value_n}
Note that values can be of any datatype like floats, strings etc., but they can also be lists or other data structures.
Keys must be unique within the dictionary. Otherwise it would be hard to extract the value by calling out a certain key, see the section about indexing and slicing below.
Keys also must be of an immutable type.
Mutability¶
Dictionaries are mutable. They can be changed after creation.
Dictionary examples¶
Some examples of dictionaries:
my_dict1 = {'axial_force': 319.2, 'moment': 74, 'shear': 23} # Strings as keys and numbers as values
my_dict2 = {1: True, 'hej': 23} # Keys are different types (ints and strings)
my_dict3 = {'Point1': [1.3, 51, 10.6], 'Point2': [7.1, 11, 6.7]} # Strings as keys and lists as values
As with most stuff in Python the flexibility is very nice, but it can also be confusing to have many different types mixed in the same data structure. To make code more readable, it is often preferred to keep the same trend throughout the dictionary. I.e. all keys are of same type and all values are of the same type.
The keys and values can be extracted separately by the methods dict.keys()
and dict.values()
:
my_dict1.keys()
my_dict1.values()
t1 = (1, 24, 56) # Simple tuple of integers
t2 = (1, 1.62, '12', [1, 2 , 3]) # Multiple types as tuple elements
points = ((4, 5), (12, 6), (14, 9)) # Tuple of tuples
Sets¶
Sets are defined with curly brackets {}. They are unordered and don't have an index. See description of indexing further down. Sets also have unique items.
The primary idea about sets is the ability to perform set operations. These are known from mathematics and can determine the union, intersection, difference etc. of two given sets.
See for example these links for explanations on set operations: https://en.wikipedia.org/wiki/Set_(mathematics)#Basic_operations or https://snakify.org/en/lessons/sets/.
A list, string or tuple can be converted to a set by set(sequence_to_convert)
. Since sets only have unique items, the set resulting from the operation has same values as the input sequence, but with duplicates removed. This can be a way to find all unique elements.
For example:
list_uniques = list(set(list_duplicates)) # Convert list to set and back to list again with now only unique elements
Mutability¶
Sets are mutable. They can be changed after creation.
Set examples¶
s1 = {32, 3, 1, 86, 6, 8}
s2 = {8, 6, 21, 7, 26}
s1.union(s2) # Find the union of the two sets
s1.intersection(s2) # Find the intersection of the two sets
list_with_duplicates = [1, 2, 3, 4, 5, 2, 2, 3, 1]
s3 = set(list_with_duplicates) # Create a set of the list (which removed duplicates)
s3
If a list is wanted again:
list(s3)
The in
operator¶
The in
operator can be used to check whether a certain item is contained in a sequence. The result of the evaluation is a boolean
(True
or False
):
2 in [1, 2, 3]
'ma' in 'Denmark'
'er' in 'Denmark'
Indexing¶
When elements are put into a sequences (strings, lists, tuples etc.), the individual elements gets an index assgined to them. This enables each element to be extracted.
Indexing in Python starts from 0, while the negative index starts from -1:
Use square brackets []¶
To extract an element by indexing, use sqaure brackets []. This is the general way and works for all sequences. Strings, lists and tuples are all sequences.
example_list = ['a', 'b', 'c', 'd']
example_list[0]
example_list[-2]
example_tuple = (10, 20, 30, 40)
example_tuple[3]
IndexError
¶
When trying to refer to an index that is not in the data structure, an IndexError
is raised:
example_tuple[10]
Extracting values from dictionaries¶
Dictionaries differ from data structures like strings, lists and tuples since they do not have an index. Instead, a value are extracted by indexing the corresponding key:
d = {'N': 83, 'My': 154, 'Mz': 317}
d['My']
Note: This means that keys in a dictionary must be unique!
See demonstation below, where the key 'a'
is defined twice. The second defintion overwrites the first one.
{'a': 1, 'b': 2, 'c':3, 'a': 4}
Slicing¶
Slicing is the operation of extracting multiple elements at once by calling out the index range. An example for slicing of a list is shown below:
Note that the stop point of the slice is not included.
These examples are shown for lists, but the same concept works for strings and tuples. Set objects do not support indexing/slicing since they are unordered, and dictionaries cannot be sliced either as they have the key functionality instead.
The most common slicing operations are:
n[start:stop] # elements from start to stop-1
n[start:] # elements from start to the end of the list
n[:stop] # elements from the beginning to stop-1
n[:] # a copy of the whole list (alternative: list.copy())
As seen, the last one creates a copy. This can be useful when working with mutable objects. For example for copying a list to mutate the copy while keeping the orginal list unchanged.
There is also setp mechanism that can be used:
a[start:stop:step] # start through not past stop, by step
Steps could be combined with the slicing operations shown above.
List methods¶
Lists have many methods for common manipulations. Methods are recognized by the 'dot'-notation, so if a method was called method_name()
, it would be used like list.method_name()
.
Some of the most common list methods are:
list.append(val) # Insert val as the last element of the list, and make list one element longer
list.pop([i]) # Remove i'th element from list and return it (if i is not provided, it defaults to last element)
list.reverse() # Reverse all elements in list
Note that these all mutate list
.
The len()
function which was used for strings in Session 1 also works for lists, dictionaries, tuples and sets. This is a function since it does not use 'dot'-notation.
Many websites have explanations about string manipulations. This is form the Python documentation itself: https://docs.python.org/3/tutorial/datastructures.html#data-structures
Note: Methods for common operations on dictionaires, tuples and sets also exist, but are not shown here.
Copying mutable objects¶
When copying objects that are mutable like, lists or dictionaries, there are some things to be aware of. This is demonstrated by a list example below.
x = [1, 2, 3]
y = x # <-- This does not make y a copy of x
y # It make y a pointer to the same underlying object (or id) as x has inside the computer
id(x) # Behind the scenes, the variable x gets assigned a unique object id
id(y) # y is seen to have the same underlying object id
This means that when we mutate (or modify) y
, the orignal list x
gets changed as well, which is often not desired. This is because it's a pointer to the same object as y.
y.append(89)
y
x # x also got 89 appended to it
Instead, the list x
should be copied either by a the list.copy()
method or by the slicing operation shown earlier.
An example is shown below by using the list.copy()
method:
x_new = [1, 2, 3] # Redefining x since it was mutated above
y_new = x_new.copy() # Copy by a method that is built-in for lists
y_new
# Append a value to y_new
y_new.append(327)
y_new
# x has not changed
x_new
# Print object id's as f-string
print(f'x_new has object id: {id(x_new)} \ny_new has object id: {id(y_new)}')
for
loops¶
The general syntax in a for
loop is
for item in iterable:
# code goes here
Recall that an iterable is a fancy word for something that can be iterated over like a string, a list, a tuple etc.
So, printing numbers from 0-5 can be done like this:
# Printing numbers from 0-5
for i in [0, 1, 2, 3, 4, 5]:
print(i)
A common way of quickly generating the numbers from 0-5 instead of typing the list [0, 1, 2, 3, 4, 5]
is by the range()
function, which has two forms:
range(stop) # Generates numbers from 0 to stop-1
range(start, stop[, step]) # Generates numbers from start to stop-1 (step is optional)
# Printing numbers from 0-5
for i in range(6):
print(i**2)
As an alternatibe to iterating over a number sequence with a counter, it is also possible to just access the each value in turn.
Here is an example where each element of a list of strings is accessed and names string
.
g = ['batman', 'superman', 'spiderman', 'ironman', 'green lantern']
h = []
for string in g: # This would be like saying: for each string in the list g
if len(string) > 7: # If the current string has more than seven characters
print(string) # Print it
while
loops¶
A while
loop is a loop that continues until some condition is no longer satisfied.
Generally, a while
will look like this:
while condition:
# code goes here
Where evaluation of condition
must return a boolean (True
or False
).
There must be some kind of change in condition
while looping. Otherwise the loop becomes an infinite loop and runs forever (or until you stop it). An example of an infinite loop is
counter = 0
while counter < 3:
print(counter) # The variable counter is never updated, so this prints forever
The counter should be updated wihtin the loop, e.g. like this:
counter = 1
while counter < 5:
print(f'The count is {counter}')
counter += 1 # Update counter (this is equivalent to: counter = counter + 1)
A while
loop can be good when the number of iterations are not known beforehand. This could be when serching for a root for an equation or finding the neutral axis of a reinforced concrete section.
When iterating for in such cases, convergence is not always ensured. A common way of exiting the while
loop is to define a max number of iterations and then check in each loop whether this number has been reached. If it has, then the loop should break
.
A similar logic to while
loops could be done with by for
loops, but a while
loop is cleaner for some purposes and can help to clarify the intetn of the code.
List comprehensions¶
List comprehensions are another way of writing a for
loop. It can be done in one line and is often cleaner and more readable for simple iteration.
General form¶
The general form of the simplest list comprehension is
result_list = [expression for item in iterable]
iterable
is a sequence that can be iterated over, this could be a list, a string, a tuple etc.item
is the counter for the iterable, think of this as the i'th elementexpression
can be anything, but will often include theitem
L1 = [12, 215, 31, 437, 51]
L2 = [2*i for i in L1] # List comprehension to multiply each element of L1 by 2
L2
Note that 2 * L1
will not create the same output, but instead repeat the list as seen below. To get a vectorized behavior like that, we could have use numpy
, which is a third party library for numerical compuations similar to Matlab.
2 * L1
List comprehension with if
statement¶
The general form of a list comprehension with a conditional is
result_list = [expression for item in iterable if condition]
iterable
is a sequence that can be iterated over, this could be a list, a string, a tuple etc.condition
is a logical condition, e.g. "item > 3", which returns a boolean (True
/False
). This can act as as filter.result_list
is a new list containingexpression
for eachitem
that fulfilled thecondition
x = [1, 2, 3, 4, 5] # Define a list (iterable)
result_list = [i for i in x if i > 3] # Filter list with list comprehension by use of condition
result_list
Form with conditional if
and else
statement¶
The general form of a list comprehension with a conditional if
and else
is:
result_list = [expression1 if condition else expression2 for item in iterable]
iterable
is a sequence that can be iterated over, this could be a list, a string, a tuple etc.condition
is a logical condition, e.g. "item > 3", which returns a boolean (True
/False
). This can act as as filter.result_list
is a new list containing elements where eachitem
depends oncondition
. If it isTrue
,expression1
is put in. Elseexpression2
is put in.
V = [3, 62, 182, 26, 151, 174]
# Set all elements of V that are less than 100 equal to 0
W = [0 if i < 100 else i for i in V]
W
List comprehensions are generally computationally faster than regular for
loops and also faster to type.
Exercise 3¶
Create a list of the unique values from the following list:
L2 = ['Hi', 'Hello', 'Hi!', 'Hey', 'Hi', 'hey', 'Hey']
Exercise 4¶
Given the dictionary
d = {2: 122, 3: 535, 't': 'T', 'rom': 'cola'}
Play around with extracting the values by calling out the keys for all key/value pairs.
Exercise 5¶
Given the list
n = [23, 73, 12, 84]
Create a for
loop that prints:
'23 sqaured is 529'
'73 sqaured is 5329'
'12 sqaured is 144'
'84 sqaured is 7056'
Exercise 6¶
Use a list comprehension to create a new list with areas of the circles that have diameters defined by
diameters = [10, 12, 16, 20, 25, 32]
Exercise 7¶
From the following list, create a new list containing only the elements that have exactly five characters.
phonetic_alphabet = ['Alpha', 'Bravo', 'Charlie', 'Delta', 'Echo', 'Foxtrot']
Exercise 8¶
Find the intersection of the two sets (elements that occur in both sets)
s1 = {'HE170B', 'HE210B', 'HE190A', 'HE200A', 'HE210A', 'HE210A'}
s2 = {'HE200A', 'HE210A', 'HE240A', 'HE200A', 'HE210B', 'HE340A'}
Exercise 9¶
Create a variable fy
and set it equal to 435.
Given the tuple below, create a list where each value is:
- The value itself if the value is below
fy
fy
if the value is larger thanfy
rebar_stresses = (125, 501, 362, 156, 80, 475, 489)
Exercise 10¶
Given the tuple below, create a list where each value is:
- 0 if the value is positive
- The value itself is the value is negative and larger than -25
- -25 if the value is lower than -25
T1 = (-18, -27, 2, -21, -15, 5)