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/08 09:58]
pdmatei
lfa:lab01-python-intro [2021/10/07 11:32] (current)
ioana.georgescu [List comprehensions]
Line 12: Line 12:
 ==== List traversal ==== ==== List traversal ====
  
-1.1. Write a function ''​f(l)''​ which determines the maximum of a list ''​l''​ of integers.+**Exercise ​1.1.** Write a function ''​f(l)''​ which determines the maximum of a list ''​l''​ of integers.
  
 <hidden The pythonic way> ​ <hidden The pythonic way> ​
Line 23: Line 23:
 </​hidden>​ </​hidden>​
  
-1.2. Modify the previous function to ''​f(l,​start,​stop)''​ and determine the maximum between positions ''​start''​ and ''​stop''​.+**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> ​ <hidden The pythonic way> ​
Line 35: Line 35:
 ==== Slicing lists ==== ==== Slicing lists ====
  
-1.3. Find the **longest** sequence of positive integers from a list. E.g. for 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]''​.+**Exercise ​1.3.** Find the **longest** sequence of positive integers from a list. E.g. for 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]''​.
  
 <hidden The pythonic way> ​ <hidden The pythonic way> ​
Line 45: Line 45:
 l[:x] l[:x]
 # the last element of a list: # the last element of a list:
-l[:-1]+l[-1]
 # the last three elements of a list: # the last three elements of a list:
-l[:-3]+l[-3:]
 # the slice from n-3 to n-1, where n is the number of elements from the list # the slice from n-3 to n-1, where n is the number of elements from the list
 l[-3:-1] l[-3:-1]
Line 53: Line 53:
 </​hidden>​ </​hidden>​
  
-1.4. Write a pythonic function to check if a list is palindrome.+**Exercise ​1.4.** Write a pythonic function to check if a list is palindrome.
  
 ===== Other datatypes ===== ===== Other datatypes =====
  
 +The most widely used datatypes in Python are lists and dictionaries. Additionally,​ at LFA, we will also use: **sets**, **stacks**.
  
 +==== Stacks ====
  
-Inner functions +In Python**lists** are also used as stacks: 
-List comprehensionsfilters +<code python> 
-Stacks +l = [] 
-Dictionaries +l.append(x) ​  # add x at the TOP of the stack (this will be the last element of the list) 
-Pairs +l[-1]         # this is the top of the stack 
-Classes and inheritance,​ instance-of +x = l.pop()   # removes and returns an element from the top of the stack. 
-toString +</​code>  ​
-Higher-order functions and lambdas +
-Unpacking ​(for tuples, lists)+
  
 +**Exercise 1.5.** Write a function which determines (and returns) the **longest** sequence of consecutive integers from a list.
  
-<hidden The Pythonic way> This text will be hidden <code python> solution </​code>​ </​hidden>​+==== 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:
  
-Python is an interpreted,​ dynamically typed language which is easy to use for scripting and prototyping applications.+<code python>​ 
 +#​create ​an empty dictionary:​ 
 +d = {}
  
-C and Java programmers quickly adjust to the Python syntax. Unlike C, in Python, lists are predefined and usually more used than arrays:+#add or modify a key-value: 
 +d[k]=v
  
-<code python>​ +#search if key k is defined in a dictionary d: 
-Comments begin with '#'​ and end at the end of the line +if k in d: 
-l = []  # ​comment +  # do something 
-l.append("​1"​) +</​code>​
-l.append(0) +
-l.append([])+
  
-print(l)+**Exercise 1.6.** Write a function which determines the number of occurrences of each character in a 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>​ </​code>​
 +</​hidden>​
 +
 +==== Sets ====
  
 +Sets are collections where each element is unique. Sets can be traversed and indexed exactly as lists. They are initialised using the constructor ''​set'':​
 <code python> <code python>
-def func(l1, l2)+# the empty set
-    ​l1.append(3+s = set() 
-    ​return l1 + l2 + 
-     +# set constructed from a list: 
-= [1+set([1,2,3]) 
-y = [2] + 
-print(func(x,​y)) +# adding a new element to the set: 
-print(x)+s.add(4)
 </​code>​ </​code>​
  
-**Remarks** +**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 ​character and a singleton string ​and strings ​are just lists; Hint 2: to create a list from another objectuse ''​list()''​).
-  * although it is possible to add type annotations, ​in Python a function'​s signature only consists of the number of parameters ​and their names +
-  * objects ​are generally passed as reference (hencewhen 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** +==== Pairs ====
-Write a function which prints EACH repeating character from a string. (Hint: strings are lists of characters).+
  
-==== Useful data structures: dictionaries ​and sets ====+Pairs are very similar to lists and can be substituted by the latter in many cases: 
 +<code python>​ 
 +(x, y)     # a pair where the first element is x and the second is y 
 +(x, y, z)  # a tuple
  
-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).+fst = p[0] 
 +snd = p[1]
  
 +for k in t:
 +  # do something with element k of the tuple
 +  ​
 +</​code>​
 +
 +===== The functional style =====
 +
 +==== Higher-order functions and lambdas ====
 +
 +The most used higher-order functions in Python are **map** and **reduce**:
 <code python> <code python>
-d = {} +from functools import reduce
-d["​X"​] = ["​X"​]+
  
-if "​X"​ in d+# adds 1 to each element of a list 
-    print("d[X] is defined in the dictionary"​)+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
     ​     ​
-if not "​Y"​ in d+def short_sum(l)
-    print("d[Y] is not defined in the dictionary"​)+   return reduce(lambda x,y:x+y,l# observe the syntax for lambdas
 </​code>​ </​code>​
  
-**Exercise 2** Write a function returns the number of repetitions of each character from a text. (Hint: use dictionaries to store the number of repetitions.)+==== List comprehensions ====
  
-**Exercise 3** Write a function returns the number of unique characters from a list.+List comprehensions are widely used programming tools in PythonUsage examples:
  
-Remark: +<code python> 
-  * a simpler way to ensure uniqueness is to use sets. +# adding 1 to each element of a list 
-  * a set may be created from a list:  ''​s ​set([1,2,3,1])''​ +l1 [x+1 for x in [1,2,3]] 
-  * and in turna list may be created from a set: ''​l = list(s)''​+# [2,3,4]
  
 +# packing elements into pairs 
 +l2 = [(x,x+1) for x in [1,2,3]]
 +# [(1,2), (2,3), (3,4)]
  
-Remark: +# unpacking pairs in the for notation 
-  ​* ​in Python we can use arbitrarily nested functions+l3 = [x+y for (x,y) in [(1,2), (2,3), (3,4)]] 
 +# [3,5,7]
  
-**Exercise 6** Write a function which searches for a list of patterns ​in a text. +# combined ​list comprehensions 
-<code python>​ +l4 = [(x,y) for x in [1,2,3] for y in [4,5,6]] 
-def find_patterns ​(pattern_listtext): +# [(14), (1, 5), (1, 6), (2, 4), (2, 5), (2, 6), (3, 4), (3, 5), (3, 6)] 
-    checks if pattern is found at position index in text + 
-    def inner_search (pattern,index):+filters 
 +l5 = [x for x in [1,2,3,4] if x>2] 
 +# [3,4]
 </​code>​ </​code>​
  
-Remark: +**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.  
-  ​Python supports functional-style programming to some extent.+ 
 +<hidden The pythonic way> ​
 <code python> <code python>
-def plus1(x): +from functools import reduce 
-    return ​+ 1+ 
 +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)
     ​     ​
-print(map(plus1,​[1,​2,​3])) +    # we return the last name and the age of the filtered list l 
-print(map(lambda x:x+1, [1,2,3]))+    return [(ln,age(cnp)) for (fn,ln,cnp) in l if cnp[0]=='2' and age(cnp) <= avg]
 </​code>​ </​code>​
 +</​hidden>​
 +
 +
 +
  
  
-**Exercise 8** Modify the previous implementation and instead of ''​for'',​ use ''​map''​ (cast the return of ''​map''​ to ''​list'':​ ''​list(map(...))''​) 
  
-However, it is more common in Python to employ //list comprehensions//​ instead of ''​map'':​ 
  
-<code python> 
-def plus1(x): 
-    return x + 1 
-    ​ 
-print([plus1(x) for x in [1,2,3]]) 
-print([(x + 1) for x in [1,2,3]])) 
-</​code>​ 
  
-List comprehensions also support the functionality of ''​filter'':​ 
  
-<code python> 
-print([(x+1) for x in [1,​2,​3,​4,​5,​6] if (x % 2 == 0)]) 
-</​code>​ 
  
-**Exercise 9** Modify the previous implementation and instead of ''​for'',​ use list comprehensions.+/*
  
 ==== Classes and inheritance ==== ==== Classes and inheritance ====
Line 236: 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.