21/12/2016 Guidance spéciale Préparation à l'examen [email protected] [email protected] Code Python (1/10) Que fait cette fonction ? def foo1(a,b) : res = False if len(a) == len(b) dic_a = {} dic_b = {} for i in a : dic_a[i] = dic_a.get(i,0)+1 for i in b : dic_b[i] = dic_b.get(i,0)+1 res = True for j in dic_a : res = res and (dic_a[j] == dic_b.get(j,0)) for j in dic_b : res = res and (dic_b[j] == dic_a.get(j,0)) return res 2 Code Python (2/10) Et celle-ci ? def foo2 (a,b): res = False if len(a) == len(b): res = True for i in a: if i in b: a.remove(i) b.remove(i) else: res = False return res 3 Code Python (3/10) ● Ces 2 fonctions font en réalité la même chose : elles vérifient toutes les deux que les 2 séquences données en paramètres contiennent exactement les mêmes éléments (pas forcément dans le même ordre). ● Il y a cependant une grosse différence entre les 2 fonctions : 4 Code Python (4/10) ● Ces 2 fonctions font en réalité la même chose : elles vérifient toutes les deux que les 2 séquences données en paramètres contiennent exactement les mêmes éléments (pas forcément dans le même ordre). ● Il y a cependant une grosse différence entre les 2 fonctions : La deuxième modifie les séquences données en paramètres, elle en retire les éléments. 5 Code Python (5/10) Examen juin 2016 Complexité (1ère fonction) ● Notons len(a) = len(b) = n ● Les parties du code les plus influentes sur la complexité sont les boucles for : Les 2 premières boucles parcourent n éléments. ( O(n) ) On considère le pire cas : les 2 dernières boucles parcourront donc aussi n éléments ( O(n) ) ● Dans les 4 boucles, on appelle la méthode get (moyenne O(1), max O(n) ) Elles sont donc équivalentes du point de vue de la complexité, on n'en considérera qu'une puisqu'elles sont en séquence. ● Au final on obtient une complexité moyenne O(n.1) = O(n) et une complexité maximale O(n.n) = O(n²) 6 Code Python (6/10) Examen juin 2016 Complexité (2ème fonction) ● Notons len(a) = len(b) = n ● La partie du code la plus influente sur la complexité est la boucle for : La boucle parcourt n éléments ( O(n) ). On appelle la méthode remove dans la boucle 2 fois mais en séquence, on peut donc n'en considérer qu'une (moyenne O(n), max O(n) ) . ● Au final on obtient une complexité moyenne égale à la complexité maximale O(n.n) = O(n²) 7 Code Python (7/10) Examen janvier 2015 Que fait cette fonction ? Faites un diagramme d'état pour chaque print en considérant que la fonction est appelée comme suit : foo4('''', ''ab'') def foo4 (res, remain): print(res) for i in range(len(remain)): foo4(res+remain[i], remain[:i]+remain[i+1:]) 8 Code Python (8/10) Examen janvier 2015 9 Code Python (9/10) Examen janvier 2015 10 Code Python (10/10) Examen juin 2016 Complexité ● Notons len(remain) = n (le remain initial) ● Dans sa boucle for, la fonction appelle récursivement n instances d'elle-même, qui appellent chacune n-1 instances d'elles-mêmes, etc ( O(n!) ). ● A chaque instance, le print est en O(n). ● Au final, la factorielle domine la complexité de la fonction, qui est donc en O(n!) 11 Opérations sur les fichiers (1/4) Examen juin 2016 On demande de créer la fonction import_dict(fname, key_idx) qui, à partir d'un fichier formaté en colonnes séparées par des « | » comme cidessous, crée un dictionnaire ayant pour clés les éléments de la colonne d'indice key_idx. A chaque clé sera associée une liste de listes contenant les éléments des autres colonnes correspondant à cette clé. Fichier exemple.txt : >>> print(import_dico(exemple.txt, 1)) Antoine|ULB|Polytech|BA1 Aurélie|UCL|Philo|BA1 Wassim|ULB|Philo|MA1 Dounia|ULG|Polytech|BA2 {'ULB': [['Antoine', 'ULB', 'Polytech', 'BA1'],['Wassim', 'ULB', 'Philo', 'MA1']], 'UCL': [['Aurélie', 'UCL', 'Philo', 'BA1']], 'ULG': [['Dounia', 'ULG', 'Polytech', 'BA2']]} 12 Opérations sur les fichiers (2/4) Examen juin 2016 1. def import_dict(fname, key_idx): 2. res = {} 3. f = open(fname) 4. lines = f.readlines() 5. f.close() 6. for l in lines: 7. data = l.strip().split('|') 8. key = data[key_idx] 9. if not key in res: 10. res[key] = [] 11. res[key].append(data) 12. return res Peut-on faire mieux ? 13 Opérations sur les fichiers (3/4) Examen juin 2016 En réalité, les lignes 9 à 11 reprennent un schémas très courant avec les dictionnaires qui consiste à créer un couple clé/valeur avec une valeur initialisée par défaut si la clé n'existe pas ou simplement modifier la valeur si la clé existe. Ces lignes deviennent donc la nouvelle ligne 9. 1. def import_dict(fname, key_idx): 2. res = {} 3. f = open(fname) 4. lines = f.readlines() 5. f.close() 6. for line in lines: 7. data = line.strip().split('|') 8. key = data[key_idx] 9. res.setdefault(key, []).append(data) 10. return res 14 Tris (1/4) Examen septembre 2016 On considère une liste d'étudiants représentés par un tuple de 4 éléments : leur nom (string), leur note sur 20 en math (int), leur note sur 20 en physique (int) et leur note sur 20 en anglais (int). On demande de trier cette liste (du meilleur étudiant au moins bon) avec un tri par selection en prenant en compte les priorités suivantes : d'abord la note en math, puis si il y a égalité la moyenne des notes et enfin la note en physique. 15 Tris (2/4) Examen septembre 2016 def moyenne(etud): return (etud[1] + etud[2] + etud[3]) / 3 def grade(etud): return 441 * etud[1] + 21 * moyenne(etud) + etud[2] def vient_avant(e1, e2): return grade(e1) > grade(e2) def echange(ls, i, j): ls[i], ls[j] = ls[j], ls[i] def tri_etudiants(ls): for i in range(len(ls) - 1): posMin = i for j in range(i + 1, len(ls)): if vient_avant(ls[j], ls[posMin]): posMin = j echange(ls, i, posMin) 16 Tris (3/4) Examen septembre 2016 Remarquez que la fonction grade n'est pas vraiment une bonne solution. Les constantes utilisées sont complètement arbitraires et le moindre changement peut entraîner des erreurs (notes sur 40 plutôt que sur 20, etc). Ici, une série de if/else imbriqués sera certes (beaucoup) plus longue mais plus rigoureuse et surtout résistante aux changements. 17 Tris (4/4) Examen janvier 2015 On demande de trier une liste de mots dans l'ordre croissant de la longueur des mots en utilisant le tri par insertion. 18 Tris (4/4) Examen janvier 2015 On demande de trier une liste de mots dans l'ordre croissant de la longueur des mots en utilisant le tri par insertion. def len_sort(words): for i in range(1, len(words)): val = words[i] j = i while j > 0 and len(words[j - 1]) > len(val): words[j] = words[j - 1] j -= 1 words[j] = val 19 Récursivité (1/2) Examen septembre 2016 On considère une liste ls dont chaque élément est soit un entier soit une sous-liste (qui peut elle-même contenir des entiers et/ou des sous-listes). On demande d'écrire la fonction récursive noEmptySublists(ls) qui fait une deepcopy de ls en ignorant les sous-listes vides. 20 Récursivité (2/2) Examen septembre 2016 def noEmptySubLists(ls): res = [] for x in ls: if type(x) == list: y = noEmptySubLists(x) if y != []: res.append(y) else: res.append(x) return res 21