Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
lfa:lab01-python-intro [2021/09/03 09:44]
pdmatei
lfa:lab01-python-intro [2021/10/07 11:32] (current)
ioana.georgescu [List comprehensions]
Line 1: Line 1:
-====== Introduction to Python ======+====== ​1. Introduction to Python ======
  
-==== Python basics ====+Python3 is a multi-paradigm language, that combines the **imperative** style with the **functional** style. It also supports Object-Oriented programming,​ albeit in a limited way. 
  
-<hidden The Pythonic way> This text will be hidden <code python> solution </​code>​ </​hidden>​+Python3 offers a few programming constructs that: 
 +  * make life real easy for the programmer,  
 +  * yield efficient programs, 
 +  * sum-up to a programming **style** called **pythonic** (a blend of imperative and functional features). ​
  
 +This lab will introduce some of these constructs.
  
-Python is an interpreted,​ dynamically typed language which is easy to use for scripting and prototyping applications.+==== List traversal ====
  
-C and Java programmers quickly adjust to the Python syntaxUnlike C, in Python, lists are predefined and usually more used than arrays:+**Exercise 1.1.** Write a function ''​f(l)''​ which determines ​the maximum of a list ''​l''​ of integers.
  
 +<hidden The pythonic way> ​
 +Traversing a list using a ''​for''​ is done as follows:
 <code python> <code python>
-# Comments begin with a '#'​ and end at the end of the line +for elem in collection: 
-l = []  ​comment +    do something
-l.append("​1"​) +
-l.append(0) +
-l.append([]) +
- +
-print(l)+
 </​code>​ </​code>​
-**Remarks** +This idiom can be used for any collection not just lists, ​as you will discover during the lab. 
-  * Although Python is strongly-typed (the interpreter keeps track and verifies the type of objects), ​lists may have different '​types'​ of elements. +</​hidden>​
-  * There exist two different major versions of Python: Python2 and Python3. Although similarthere are some incompatible differences between them. We will use Python3, so take care when researching documentation.+
  
 +**Exercise 1.2.** Modify the previous function to ''​f(l,​start,​stop)''​ and determine the maximum between positions ''​start''​ and ''​stop''​.
 +
 +<hidden The pythonic way> ​
 +When we care about the indices of a list, we can use the function ''​range(x,​y)''​ which returns **a list of integers** starting from ''​x''​ until ''​y-1''​.
 <code python> <code python>
-for i in range(0,​len(l)): +for i in range(0,​len(collection)): 
-    ​print(l[i])+    ​# do something with collection[i] 
 +</​code>​ 
 +</​hidden>​
  
-print(range(0,​len(l)))+==== Slicing lists ====
  
-for elem in l: +**Exercise 1.3.** Find the **longest** sequence of positive integers from a listE.gfor the list ''​[1,​3,​-1,​2,​0,​1,​5,​4,​-2,4,5,-3,0,1,2]'' ​the answer is ''​[2,0,1,5,4]''​.
-    print(elem) +
-</​code>​ +
-**Remarks** +
-  * List traversal may be achieved using indexingIndexes are integers taken from a range''​range(0,​len(l))''​ is a list in itself. +
-  ​Lists (and other data structures) can be iterated using ''​in''​ +
- +
-**Syntax** +
-  ​unlike C or Java where we often use ''​{...}'' ​for scopingin Python we use indentation levels (either a tab or spaces)  +
-  * control instructions such as ''​for''​, ''​while'',​ ''​if''​ do not require ''​(...)''​ for conditions but they must end with '':''​+
  
 +<hidden The pythonic way> ​
 +Python supports various list slicing operations, as well as "​overloaded"​ indexing:
 <code python> <code python>
-def func(l1, l2)+# the sublist from positions 0 to x of l
-    ​l1.append(3) +l[0:x] 
-    ​return l1 + l2 +# the very same list: 
-    ​ +l[:x
-[1] +# the last element of a list: 
-y = [2+l[-1] 
-print(func(x,y)) +# the last three elements of a list: 
-print(x)+l[-3:
 +# the slice from n-3 to n-1where n is the number of elements from the list 
 +l[-3:-1]
 </​code>​ </​code>​
 +</​hidden>​
  
-**Remarks** +**Exercise 1.4.** Write a pythonic function ​to check if a list is palindrome.
-  * although it is possible ​to add type annotations,​ in Python ​function'​s signature only consists of the number of parameters and their names +
-  * objects are generally passed as reference (hence, when printing ''​x'',​ we see the list ''​[1,​3]''​) (for details see: [[https://​docs.python.org/​3/​reference/​datamodel.html | Python data model]]) +
-  * ''​+''​ denotes list concatenation+
  
-**Exercise 1** +===== Other datatypes =====
-Write a function which prints EACH repeating character from a string. (Hint: strings are lists of characters).+
  
-==== Useful data structures: dictionaries ​and sets ====+The most widely used datatypes in Python are lists and dictionaries. Additionally,​ at LFA, we will also use: **sets**, **stacks**.
  
-Dictionaries are another useful data structure. A dictionary is a ''<​key>​ : <​value>''​ mapping. Unlike lists, keys may be of any type (integers, strings, or any other datatype).+==== Stacks ====
  
 +In Python, **lists** are also used as stacks:
 <code python> <code python>
 +l = []
 +l.append(x) ​  # add x at the TOP of the stack (this will be the last element of the list)
 +l[-1]         # this is the top of the stack
 +x = l.pop() ​  # removes and returns an element from the top of the stack.
 +</​code>  ​
 +
 +**Exercise 1.5.** Write a function which determines (and returns) the **longest** sequence of consecutive integers from a list.
 +
 +==== Dictionaries ====
 +
 +Python dictionaries are actually **hash maps** (or **hash tables**). The keys ''​k''​ are **dispersed** using a hash-function into buckets. Each bucket will hold its respective values. Some examples of dictionary usage:
 +
 +<code python>
 +#create an empty dictionary:
 d = {} d = {}
-d["​X"​] = ["​X"​] 
  
-if "​X"​ in d+#add or modify a key-value
-    ​print("​d[X] is defined in the dictionary") +d[k]=v 
-    ​ + 
-if not "​Y" ​in d: +#search if a key k is defined in dictionary ​d: 
-    ​print("​d[Y] is not defined in the dictionary"​)+if in d: 
 +  # do something
 </​code>​ </​code>​
  
-**Exercise ​2** Write a function ​returns ​the number of repetitions ​of each character ​from text. (Hint: use dictionaries to store the number of repetitions.)+**Exercise ​1.6.** Write a function ​which determines ​the number of occurrences ​of each character ​in string 
 +<hidden The pythonic way>  
 +<code python>​ 
 +def count(l)
 +   d = {} 
 +   for x in l: 
 +      if x in d: 
 +         d[x] += 1 
 +      else: 
 +         d[x] = 1 
 +   ​return d 
 +</​code>​ 
 +</​hidden>​
  
-**Exercise 3** Write a function returns the number of unique characters from a list.+==== Sets ====
  
-Remark: +Sets are collections where each element ​is uniqueSets can be traversed and indexed exactly as lists. They are initialised using the constructor ​''​set''​: 
-  * a simpler way to ensure uniqueness ​is to use sets. +<code python>​ 
-  * a set may be created from a list:  ​''​s = set([1,2,3,1])''​ +# the empty set: 
-  * and in turn, a list may be created from a set: ''​l ​list(s)''​+set()
  
-**Exercise 4** Write function which takes a pattern and a text and prints all indexes where an occurrence of pattern in text are found.+# set constructed from list: 
 +s = set([1,​2,​3])
  
-Remark+# adding a new element to the set
-  * lists can be sliced in Python using the following syntax: ''​l[start_index:​end_index]''​ Test it to see how slicing is performed.+s.add(4) 
 +</​code>​
  
-**Exercise ​5** Modify ​the previous implementation ​to use slicing.+**Exercise ​1.7.** Determine ​the list of characters which occur in a string. E.g. for "​limbajeformale"​ we have: "​limbajefor"​. (Hint 1: in Python there is no difference between a character and a singleton string and strings are just lists; Hint 2: to create a list from another object, ​use ''​list()''​).
  
-Remark: +==== Pairs ====
-  * in Python we can use arbitrarily nested functions+
  
-**Exercise 6** Write a function which searches for a list of patterns ​in a text.+Pairs are very similar to lists and can be substituted by the latter ​in many cases:
 <code python> <code python>
-def find_patterns ​(pattern_listtext)+p = (xy    ​a pair where the first element ​is x and the second is y 
-    ​checks if pattern ​is found at position index in text +t = (xy, z # a tuple 
-    def inner_search ​(pattern,index):+ 
 +fst = p[0] 
 +snd = p[1] 
 + 
 +for k in t: 
 +  # do something with element k of the tuple 
 +  ​
 </​code>​ </​code>​
  
-Remark: +===== The functional style ===== 
-  * Python supports ​functional-style programming to some extent.+ 
 +==== Higher-order functions and lambdas ==== 
 + 
 +The most used higher-order functions in Python are **map** and **reduce**:
 <code python> <code python>
-def plus1(x): +from functools import reduce 
-    return x + 1+ 
 +# adds 1 to each element of a list 
 +def allplus1(l): 
 +   ​return ​map(lambda x:x+1,l) 
 + 
 +# computes the sum of elements of a list 
 +def sum_l (l): 
 +   # inner functions are very useful for defining local, reusable functionality 
 +   def plus(x,​y):​ 
 +      return x + y 
 +   ​return reduce(plus,​l) # reduce is a little different from Haskell folds: it does not use an initial value
     ​     ​
-print(map(plus1,​[1,​2,​3])+def short_sum(l): 
-print(map(lambda x:x+1[1,2,3]))+   return reduce(lambda x,y:x+y,l# observe the syntax for lambdas
 </​code>​ </​code>​
  
 +==== List comprehensions ====
  
-**Exercise 8** Modify the previous implementation and instead of ''​for'',​ use ''​map''​ (cast the return of ''​map''​ to ''​list'':​ ''​list(map(...))''​) +List comprehensions are widely used programming tools in Python. Usage examples:
- +
-However, it is more common ​in Python ​to employ //list comprehensions//​ instead of ''​map''​:+
  
 <code python> <code python>
-def plus1(x): +# adding 1 to each element of a list 
-    ​return ​x + 1 +l1 = [x+1 for x in [1,2,3]] 
-     +# [2,3,4] 
-print([plus1(x) for x in [1,2,3]]) + 
-print([(x + 1) for x in [1,2,3]]))+# packing elements into pairs  
 +l2 = [(x,x+1) for x in [1,2,3]] 
 +[(1,2), (2,3), (3,4)] 
 + 
 +# unpacking pairs in the for notation 
 +l3 = [x+y for (x,y) in [(1,2), (2,3), (3,4)]] 
 +# [3,5,7] 
 + 
 +# combined list comprehensions 
 +l4 = [(x,y) for x in [1,​2,​3] ​for y in [4,5,6]
 +# [(1, 4), (1, 5), (1, 6), (2, 4), (2, 5), (2, 6), (3, 4), (3, 5), (3, 6)] 
 + 
 +# filters 
 +l5 = [x for x in [1,2,3,4] if x>2] 
 +# [3,4]
 </​code>​ </​code>​
  
-List comprehensions also support ​the functionality ​of ''​filter''​:+**Exercise 1.8.** Write a function which takes a list of records //first name, last name, CNP// (encoded as tuples), and returns a list of **the last names** and **ages** ​of all females which are younger than the average of the entire list. E.g. ''​[ ("​Mary",​ "​Smith",​ "​2030602123456"​),​ ("​Anne",​ "​Doe",​ "​2121092123456"​),​ ("​Matei",​ "​Dan",​ "​1121202123456"​),​ ("​Maggie",​ "​Byrne",​ "​2121078123456"​)]''​ yields ''​[("​Smith",​19),​ ("​Doe",​29)]'​'. Maggie was born in '78, whereas Mary, Anne and Matei were born in '94, '92 and 2002, respectively. ​
  
 +<hidden The pythonic way> ​
 <code python> <code python>
-print([(x+1) for x in [1,2,3,4,​5,​6] ​if (x % 2 == 0)])+from functools import reduce 
 + 
 +def getYouth(l): 
 + # this function computes the age of a given CNP 
 +    def age(cnp): 
 +        # conversion to integer of the two-character year code 
 +        if int(cnp[5:8]) <= 21: 
 +            return 2021 - int("​20"​+cnp[5:7]) 
 +        else: 
 +            return 2021 - int("​19"​+cnp[5:​7]) 
 +     
 +    # computing the average ages (a map could have also been used) 
 +    avg = reduce(lambda a,b:a+b, [age(x[-1]) for x in l]) / len(l) 
 +     
 +    # we return the last name and the age of the filtered list l 
 +    return ​[(ln,age(cnp)) for (fn,ln,cnp) in l if cnp[0]=='​2'​ and age(cnp<= avg]
 </​code>​ </​code>​
 +</​hidden>​
 +
 +
 +
 +
 +
 +
 +
 +
 +
  
-**Exercise 9** Modify the previous implementation and instead of ''​for'',​ use list comprehensions.+/*
  
 ==== Classes and inheritance ==== ==== Classes and inheritance ====
Line 195: Line 279:
   * Extend the class example shown previously to include class ''​Node''​ which models non-empty trees. Implement methods ''​size''​ and ''​contains''​.   * Extend the class example shown previously to include class ''​Node''​ which models non-empty trees. Implement methods ''​size''​ and ''​contains''​.
  
 +
 +*/
 +
 +===== Practice =====
 +
 +A labelled graph is encoded as a file where:
 +  * **the first line** consists of the number of nodes
 +  * **each subsequent line** is an edge ''<​from>​ <​label>​ <​to>''​
 +Example:
 +<​code>​
 +5
 +0 X 1
 +1 O 2 
 +1 X 3
 +1 O 4
 +4 X 1
 +3 O 2
 +</​code>​
 +
 +  * Suppose we encode streets as labelled graphs, where each label '​X'​ or '​O'​ denotes if a street is closed or open. 
 +  * Compute the set of accessible nodes from a given **source**, via open streets.
 +  * (Hint1: google //Python read lines// to see how to read from a file; also, google ''​split''​ in Python)
 +  * (Hint2: you will need a dictionary to store, for each node and label l, the list of its l-successors)
 +
 +
 +===== Haskell practice =====
 +
 +Solve the same exercise, only build your own input as a string, instead of a file.