This repository has been archived on 2019-08-09. You can view files and clone it, but cannot push or open issues or pull requests.
s1-tp/S2/TP2/tp2.py
Geoffrey Frogeye dd91bd7d48 Fix commit précédent
Pylint me l'avait gentilment fait remarquer mais c'était innondé sous
les avertissements 'already defined from outerscope'...
2015-02-09 18:50:01 +01:00

514 lines
12 KiB
Python

# PREUD'HOMME Geoffrey
# BEAUSSART Jean-loup
# Donné le 27/01/2015
# TP2 Anagrammes - Dictionnaires
# http://www.fil.univ-lille1.fr/~L1S2API/CoursTP/tp2_dictionnaires.html
def partie(nom):
print('\n', nom, '=' * len(nom), sep='\n')
def section(nom):
print('\n', nom, '-' * len(nom), sep='\n')
def question(numero):
print('\n***', 'Question', numero, '***')
partie('Quelques méthodes sur les listes et les chaînes') # Geoffrey
section('Méthode split')
question(1)
print(">>> s = 'la méthode split est parfois bien utile'")
s = 'la méthode split est parfois bien utile'
print(">>> s.split (' ')")
print(s.split(' '))
print(">>> s.split ('e')")
print(s.split('e'))
print(">>> s.split ('é')")
print(s.split('é'))
print(">>> s.split ()")
print(s.split())
print(">>> s.split ('')")
print('ValueError: empty separator')
print(">>> s.split ('split')")
print(s.split('split'))
question(2)
print(
'La méthode `split` renvoie la liste des chaînes de la découpe de la chaîne sur laquelle est appliquée la fonction par la chaîne passée en argument (ou à défaut le caractères d\'espacement')
question(3)
# TODO utf-8
# TODO en print
print(">>> s = 'la méthode split est parfois bien utile'")
s = 'la méthode split est parfois bien utile'
print(">>> s.split(' ')")
print(s.split(' '))
print('>>> s')
print('\'' + s + '\'')
print(
'De par cet exemple, on remarque que s reste la même chaîne de caractère, `split` ne modifie donc pas la chaîne de caractères à laquelle elle s\'applique (ce qui est logique vu le caractère non-mutable des chaînes de caractères')
section('Méthode join')
question(1)
print(">>> s = 'la méthode split est parfois bien utile'")
s = 'la méthode split est parfois bien utile'
print('>>> l = s.split()')
l = s.split()
print('>>> "".join (l)')
print("".join(l))
print('>>> " ".join (l)')
print(" ".join(l))
print('>>> ";".join (l)')
print(";".join(l))
print('>>> " tralala ".join (l)')
print(" tralala ".join(l))
print('>>> "\n".join (l)')
print("\n".join(l))
print('>>> "".join (s)')
print("".join(s))
print('>>> "!".join (s)')
print("!".join(s))
print('>>> "".join ()')
print('TypeError: join() takes exactly one argument (0 given)')
print('>>> "".join ([])')
print("".join([]))
print('>>> "".join ([1,2])')
print('TypeError: sequence item 0: expected str instance, int found')
question(2)
print(
'La méthode join concatène les chaînes de caractères contenues dans la liste passée en paramètre, en insérant entre deux la chaîne de caractère sur laquelle elle est appliquée.')
question(3)
print('>>> chaine = \'!\'')
chaine = '!'
print('>>> chaine.join(l)')
print(chaine.join(l))
print('>>> chaine')
print('\'' + chaine + '\'')
print(
'De par cet exemple, on remarque que chaine reste la même chaîne de caractères, `join` ne modifie donc pas la chaîne de caractères à laquelle elle s\'applique (ce qui est logique vu le caractère non-mutable des chaînes de caractères')
question(4)
def join(chaine, sequence):
# TODO Docstring
res = ''
l = len(sequence)
for i in range(l):
res += sequence[i]
if i < l - 1:
res += chaine
return res
print(">>> join('.', ['raymond', 'calbuth', 'ronchin', 'fr'])")
print(join('.', ['raymond', 'calbuth', 'ronchin', 'fr']))
section('Méthode sort')
question(1)
print('>>> l = list (\'timoleon\')')
l = list('timoleon')
print('>>> l.sort()')
l.sort()
print('>>> l')
print(l)
print('La méthode sort semble trier les lettres par ordre alphabétique')
print('>>> s = "Je n\'ai jamais joué de flûte."')
s = "Je n'ai jamais joué de flûte."
print('>>> l = list (s)')
l = list(s)
print('>>> l.sort()')
l.sort()
print('>>> l')
print(l)
print(
'La méthode sort trie aussi les caractères spéciaux : ponctuation au début, accents à la fin')
print(
'Il semblerait que la méthode sort trie les caractères de s selon l\'ordre croissant de leur numéro de code ASCII (ou tout encodage utilisé)')
question(2)
print('>>> l = [\'a\', 1]')
l = ['a', 1]
print('>>> l.sort()')
print('TypeError: unorderable types: int() < str()')
print(
'On obtient une erreur comme quoi les types str et int ne sont pas ordonnable. En effet, il n\'est pas logique d\'ordonner des caractères avec des chiffres.')
print(
'Notons qu\'il aurait très bien pu être possible que cette méthode utilise le code des caractères, puisque celui-ci est de type int, comme c\'était le cas avec Python 2.')
section('Une fonction sort pour les chaînes')
question(1)
def sort(chaine):
# TODO Docstring
# TODO On peut pas faire plus court ?
l = list(chaine)
l.sort()
return ''.join(l)
print('>>> sort(\'timoleon\')')
print(sort('timoleon'))
partie('Anagrammes') # Jean-loup
question(1)
def sont_anagrammes1(chaine1, chaine2):
"""
Indique si chaine1 et chaine2 sont anagrammes
str, str → bool
CU : chaine1 et chaine2 sont des str
"""
assert(type(chaine1) == type(chaine2) ==
str), 'chaine1 et chaine2 doivent être des str'
# Si la longueur est différente, ça ne peut pas être des anagrammes
if len(chaine1) != len(chaine2):
return False
c1 = sort(chaine1)
c2 = sort(chaine2)
return c1 == c2
question(2)
def sont_anagrammes2(chaine1, chaine2):
"""
Indique si chaine1 et chaine2 sont anagrammes
str, str → bool
CU : chaine1 et chaine2 sont des str
"""
assert(type(chaine1) == type(chaine2) ==
str), 'chaine1 et chaine2 doivent être des str'
# Si la longueur est différente, ça ne peut pas être des anagrammes
if len(chaine1) != len(chaine2):
return False
occu1 = dict((i, chaine1.count(i)) for i in chaine1)
occu2 = dict((i, chaine2.count(i)) for i in chaine2)
return occu1 == occu2
question(3)
def sont_anagrammes3(chaine1, chaine2):
"""
Indique si chaine1 et chaine2 sont anagrammes
str, str → bool
CU : chaine1 et chaine2 sont des str
"""
assert(type(chaine1) == type(chaine2) ==
str), 'chaine1 et chaine2 doivent être des str'
# Si la longueur est différente, ça ne peut pas être des anagrammes
if len(chaine1) != len(chaine2):
return False
for i in chaine1:
if chaine1.count(i) != chaine2.count(i):
return False
return True
section('Casse et accentuation')
question(1)
EQUIV_NON_ACCENTUE = {'é': 'e', 'è': 'e', 'à ': 'a', 'ç': 'c',
'î': 'i', 'ï': 'i', 'ô': 'o', 'ê': 'e', 'ë': 'e', 'â': 'a', 'û': 'u'}
question(2)
def bas_casse_sans_accent(chaine):
"""
Renvoie l'équivalent minuscule non accentuée de la chaîne passée en paramètre
str → str
CU : chaine est un str
"""
assert(type(chaine) == str), 'chaine doit être un str'
chaineCpy = chaine.lower()
ret = ""
for i in chaineCpy:
if i in EQUIV_NON_ACCENTUE:
ret += EQUIV_NON_ACCENTUE[i]
else:
ret += i
return ret
question(3)
def sont_anagrammes_sans_casse_ni_accent(chaine1, chaine2):
"""
Indique si chaine1 et chaine2 sont anagrammes sans de tenir compte de la casse ni des accents
str, str → bool
CU : chaine1 et chaine2 sont des str
"""
assert(type(chaine1) == type(chaine2) ==
str), 'chaine1 et chaine2 doivent être des str'
# Si la longueur est différente, ça ne peut pas être des anagrammes
if len(chaine1) != len(chaine2):
return False
chaine1Cpy = bas_casse_sans_accent(chaine1)
chaine2Cpy = bas_casse_sans_accent(chaine2)
# TODO Voir quelle est la meilleure méthode
return sont_anagrammes2(chaine1Cpy, chaine2Cpy)
partie('Recherche d\'anagrammes') # Jean-loup
section('Le lexique')
# TODO Question 1 ?
question(2)
from lexique import *
question(3)
print('Il y a %d mots dans le lexique' % len(LEXIQUE))
question(4)
test = len(LEXIQUE) == len(set(LEXIQUE))
# Bien que l'on ai vu en cours que cette méthode n'est pas la plus économique en mémoire, c'est
# bizarrement la plus rapide
print('Le test a retourné %s.' % test)
section('Anagrammes d\'un mot : première méthode')
question(1)
def anagrammes(mot):
"""
Recherche les anagrammes de mot
str → [str *]
CU : mot est un str
"""
assert(type(mot) == str), 'mot doit être un str'
return [i for i in LEXIQUE if sont_anagrammes_sans_casse_ni_accent(i, mot)]
question(2)
for a in ['Orange', 'Calbuth']:
print('Les anagrammes de %s sont %s.' % (a, ', '.join(anagrammes(a))))
section('Anagrammes d\'un mot : seconde méthode')
question(1)
print('Il se peut que certains mots du lexique soient des anagrammes d\'autres mots du lexique,\
or on se retrouverait alors avec plusieurs fois la même liste d\'anagrammes \
pour des clés différentes.')
question(2)
def cle(mot):
"""
Renvoie la version triée des lettres en minuscule et sans accents de mot
str → str
CU : mot est un str
"""
assert(type(mot) == str), 'mot doit être un str'
cpy = bas_casse_sans_accent(mot)
return sort(cpy)
question(3)
ANAGRAMMES = dict()
for i in LEXIQUE:
k = cle(i)
if not k in ANAGRAMMES:
ANAGRAMMES[k] = [i]
else:
ANAGRAMMES[k] = ANAGRAMMES[k] + [i]
print('Le dictionnaire des anagrammes contient %d entrées' % len(ANAGRAMMES))
question(4)
def anagrammes2(mot):
"""
Recherche les anagrammes de mot
str → [str *]
CU : mot est un str
"""
assert(type(mot) == str), 'mot doit être un str'
k = cle(mot)
if k in ANAGRAMMES:
return ANAGRAMMES[k]
else:
return []
question(5)
for a in ['Orange', 'Calbuth']:
print('Les anagrammes de %s sont %s.' % (a, ', '.join(anagrammes2(a))))
section('Comparaison des deux méthodes')
question(1)
NB_TESTS = 30 # Mettre à 0 pour réduire l'attente
import time
debut = time.time()
for i in range(NB_TESTS):
anagrammes(LEXIQUE[i])
temps1 = time.time() - debut
debut = time.time()
for i in range(NB_TESTS):
anagrammes2(LEXIQUE[i])
temps2 = time.time() - debut
print('La première méthode a duré %s secondes, et la deuxième %s secondes.' % (temps1, temps2),
'La deuxième méthode est %0.2f fois plus efficace que la première.' % (temps1 / temps2),
'En effet, la première vérifie %d combinaisons d\'anagrammes, alors que la deuxième ne \
réalise qu\'un accès à un dictionnaire. Notons que la construction dudit dictionnaire a lui aussi \
pris un certain temps, mais reste négligeable par rapport à la première méthode.' % len(LEXIQUE),
sep='\n')
partie('Phrases d\'anagrammes') # Geoffrey
question(1)
# TODO Texte explicatif du concept d'arbres
def liste_possibilites(arbre, precede):
# dict → list
# TODO Docstring
# {1: {3: None}, {4: None}, 2: None} ⇒ [[1, 3], [1, 4], 2]
possibilites = []
for i in arbre:
if type(arbre[i]) == dict:
possibilites = possibilites + \
liste_possibilites(arbre[i], precede + [i])
elif arbre[i] == None:
possibilites = possibilites + [precede + [i]]
return possibilites
def annagrammes_arbre(liste):
# TODO Docstring
# En supposant que (1, 3) et (2, 4) sont anagrammes
# [1, 2] ⇒ {1: {2: None, 4: None}, 3: {2: None, 4: None}}
anagrammesPremier = anagrammes(liste[0])
if len(liste) > 1: # Si il y a des anagrammes après
return dict((i, annagrammes_arbre(liste[1:])) for i in anagrammesPremier)
else:
return dict((i, None) for i in anagrammesPremier)
def annagrammes_phrase(phrase):
# TODO Docstring
mots = phrase.split()
arbre = annagrammes_arbre(mots)
liste = liste_possibilites(arbre, [])
return [' '.join(i) for i in liste]
print('>>> annagrammes_phrase(\'Mange ton orange\')')
print(annagrammes_phrase('Mange ton orange'))
partie('Sauvegarde et récupération')
ANAGRAMMES_FICHIER = 'anagrammes.txt'
question(1)
def sauver_dico():
f = open(ANAGRAMMES_FICHIER, 'w')
for i in ANAGRAMMES:
f.write(i + ':' + ':'.join(ANAGRAMMES[i]) + '\n')
f.close()
question(2)
sauver_dico()
from os.path import getsize
taille = getsize(ANAGRAMMES_FICHIER)
print('Le dictionnaire fait %d octets, soit %0.3f Mio.' %
(taille, taille / 1024 / 1024))
question(3)
def charger_dico():
ANAGRAMMES = dict()
f = open(ANAGRAMMES_FICHIER, 'r')
for l in f:
decoupe = ':'.split(str(l))
ANAGRAMMES[decoupe[0]] = decoupe[1:]
f.close()