diff --git a/3.7-DicoOrd.py b/3.7-DicoOrd.py new file mode 100644 index 0000000..b55ff4d --- /dev/null +++ b/3.7-DicoOrd.py @@ -0,0 +1,202 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" + Author: freezed 2018-01-25 + Version: 0.1 + Licence: `GNU GPL v3`: http://www.gnu.org/licenses/ +""" + + +class DictionnaireOrdonne: + + """ + Dictionnaire ordonne + ==================== + + Objet ressemblant a un dict, avec des capacitees de tri. + + Les cles et valeurs se trouvant dans des listes de meme + taille, il suffira de prendre l'indice dans une liste pour + savoir quel objet lui correspond dans l'autre. Par exemple, + la cle d'indice 0 est couplee avec la valeur d'indice 0. + + On doit pouvoir ajouter deux dictionnaires ordonnes + (dico1 + dico2) ; les cles et valeurs du second dictionnaire + sont ajoutees au premier. + + :Example: + >>> fruits = DictionnaireOrdonne() + >>> fruits + {} + + >>> fruits["pomme"] = 52 + >>> fruits["poire"] = 34 + >>> fruits["prune"] = 128 + >>> fruits["melon"] = 15 + >>> fruits + {'pomme': 52, 'poire': 34, 'prune': 128, 'melon': 15} + + >>> fruits.sort() + >>> print(fruits) + {'melon': 15, 'poire': 34, 'pomme': 52, 'prune': 128} + + >>> legumes = DictionnaireOrdonne(carotte = 26, haricot = 48) + >>> print(legumes) + {'carotte': 26, 'haricot': 48} + + >>> len(legumes) + 2 + + #>>> legumes.reverse() + #>>> fruits = fruits + legumes + #>>> fruits + #{'melon': 15, 'poire': 34, 'pomme': 52, + #'prune': 128, 'haricot': 48, 'carotte':26} + + #>>> del fruits['haricot'] + #>>> 'haricot' in fruits + #False + + #>>> legumes['haricot'] + #48 + + #>>> for cle in legumes: + #... print(cle) + #... + #haricot + #carotte + + #>>> legumes.keys() + #['haricot', 'carotte'] + + #>>> legumes.values() + #[48, 26] + + #>>> for nom, qtt in legumes.items(): + #... print("{0} ({1})".format(nom, qtt)) + #... + #haricot (48) + #carotte (26) + """ + + def __init__(self, **dico): + """ + On doit pouvoir creer le dictionnaire de plusieurs façons : + - Vide: sans passer aucun parametre + - Copie d'un dict(): parametre du constructeur un dict() que + l'on copie par la suite dans notre objet. On peut ainsi + ecrire constructeur(dictionnaire) et les cles et valeurs + contenues dans le dictionnaire sont copiees dans l'objet + construit. + - Pre-rempli de cles/valeurs en parametre: comme les dict() + usuels, on doit ici avoir la possibilite de pre-remplir + notre objet avec des couples cles-valeurs passes en + param (constructeur(cle1 = valeur1, cle2 = valeur2, …)) + Les cles et valeurs doivent etre couplees + """ + + self.kl = list() + self.vl = list() + + if len(dico) != 0: + for k, v in dico.items(): + self.kl.append(k) + self.vl.append(v) + + def __repr__(self): + """ + Affiche l'objet dans l'interpreteur ou grâce a la fonction + print. L'affichage identique aux dict() + ({cle1: valeur1, cle2: valeur2, …}). + """ + content = list() + + if len(self.kl) != 0: + for i in range(0, len(self.kl)): + content.append("'{}': {}".format(self.kl[i], self.vl[i])) + + return "{0}{1}{2}".format( + "{", + ", ".join(content), + "}" + ) + + def __setitem__(self, cle, valeur): + """ + Acces avec crochets pour modif (objet[cle] = valeur) + Si la cle existe on ecrase l'ancienne valeur, si elle + n'existe pas on ajoute le couple cle-valeur a la fin + """ + try: + index = self.kl.index(cle) + self.kl[index] = cle + self.vl[index] = valeur + + except ValueError: + self.kl.append(cle) + self.vl.append(valeur) + + def sort(self, reverse=False): + """ + L'objet doit definir les methodes sort pour le trier et reverse + pour l'inverser. Le tri de l'objet doit se faire en fonction + des cles + """ + # pour trier on stocke les couples de cle & valeur sous forme + # de tuple dans une liste temporaire + liste_temporaire = list() + + if len(self.kl) != 0: # Seulement si il y a des donnees + for i in range(0, len(self.kl)): # on parcour chaque entee + liste_temporaire.append((self.kl[i], self.vl[i])) + + # Tri des tuples par la valeur par une comprension de liste + liste_permute = [(val, cle) for cle, val in liste_temporaire] + liste_triee = [(cle, val) for val, cle in sorted(liste_permute, reverse=reverse)] + + # On range les donnees tries dans attributs de l'objet + self.kl = [cle for cle, val in liste_triee] + self.vl = [val for cle, val in liste_triee] + + def __len__(self): + """ Retourne la taille de l'objet grace a la fonction len """ + return len(self.kl) + + #def __contains__(): + #""" Cherche une cle dans notre objet (cle in dictionnaire) """ + + #def __delattr__(self): + #""" + #Les cles et valeurs doivent etre couplees. Si on cherche + #a supprimer une cle sa valeur doit etre supprimee. + #""" + + #def __getitem__(): + #""" Acces avec crochets pour recuperer une valeur (objet[cle]) """ + + #def __delitem__(): + #""" Acces avec crochets pour suppression (del objet[cle]) """ + + #def __setattr__(): + #""" Function doc """ + + #def generateur(): + #""" + #L'objet doit pouvoir etre parcouru. + #Quand on ecrit for cle in dictionnaire, on doit parcourir + #la liste des cles contenues dans le dictionnaire. A l'instar + #des dictionnaires, trois methodes keys() (renvoyant la liste + #des cles), values() (renvoyant la liste des valeurs) et + #items() (renvoyant les couples (cle, valeur)) doivent etre + #mises en œuvre. Le type de retour de ces methodes est laisse + #a votre initiative : il peut s'agir d'iterateurs ou de + #generateurs (tant qu'on peut les parcourir). + #""" + + +if __name__ == "__main__": + """ Active les doctests """ + + import doctest + doctest.testmod() diff --git a/package/dico_ord-correction.py b/package/dico_ord-correction.py new file mode 100644 index 0000000..8de2ced --- /dev/null +++ b/package/dico_ord-correction.py @@ -0,0 +1,257 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Author: freezed 2018-01-25 +Version: 0.1 +Licence: `GNU GPL v3`: http://www.gnu.org/licenses/ +""" + + +class DictionnaireOrdonne: + + """ + + Dictionnaire ordonne + ==================== + + Notre dictionnaire ordonné. L'ordre des données est maintenu + et il peut donc, contrairement aux dictionnaires usuels, être trié + ou voir l'ordre de ses données inversées + + + :Example: + >>> fruits = DictionnaireOrdonne() + >>> fruits + {} + + >>> fruits["pomme"] = 52 + >>> fruits["poire"] = 34 + >>> fruits["prune"] = 128 + >>> fruits["melon"] = 15 + >>> fruits + {'pomme': 52, 'poire': 34, 'prune': 128, 'melon': 15} + + >>> fruits.sort() + >>> print(fruits) + {'melon': 15, 'poire': 34, 'pomme': 52, 'prune': 128} + + >>> legumes = DictionnaireOrdonne(carotte = 26, haricot = 48) + + # Test possible seulement avec python 3.6, + # voir: www.python.org/dev/peps/pep-0468/ + #>>> print(legumes) + #{'carotte': 26, 'haricot': 48} + + >>> len(legumes) + 2 + + >>> legumes.reverse() + + >>> fruits = fruits + legumes + >>> fruits + {'melon': 15, 'poire': 34, 'pomme': 52, 'prune': 128, 'haricot': 48, 'carotte': 26} + + >>> del fruits['haricot'] + + >>> 'haricot' in fruits + False + + >>> 'pomme' in fruits + True + + >>> legumes['haricot'] + 48 + + >>> for cle in legumes: + ... print(cle) + ... + haricot + carotte + + >>> fruits.keys() + ['melon', 'poire', 'pomme', 'prune', 'carotte'] + + >>> legumes.keys() + ['haricot', 'carotte'] + + >>> fruits.values() + [15, 34, 52, 128, 26] + + >>> legumes.values() + [48, 26] + + >>> for nom, qtt in legumes.items(): + ... print("{0} ({1})".format(nom, qtt)) + ... + haricot (48) + carotte (26) + + >>> mots = {'olive': 51, 'identite': 43, 'mercredi': 25, 'prout': 218, 'assiette': 8, 'truc': 26} + >>> mots_ordonne = DictionnaireOrdonne(mots) + >>> mots_ordonne.sort() + >>> mots_ordonne + {'assiette': 8, 'identite': 43, 'mercredi': 25, 'olive': 51, 'prout': 218, 'truc': 26} + """ + + def __init__(self, base={}, **donnees): + """Constructeur de notre objet. Il peut ne prendre aucun paramètre + (dans ce cas, le dictionnaire sera vide) ou construire un + dictionnaire remplis grâce : + - au dictionnaire 'base' passé en premier paramètre ; + - aux valeurs que l'on retrouve dans 'donnees'.""" + + self._cles = [] # Liste contenant nos clés + self._valeurs = [] # Liste contenant les valeurs correspondant à nos clés + + # On vérifie que 'base' est un dictionnaire exploitable + if type(base) not in (dict, DictionnaireOrdonne): + raise TypeError( \ + "le type attendu est un dictionnaire (usuel ou ordonne)") + + # On récupère les données de 'base' + for cle in base: + self[cle] = base[cle] + + # On récupère les données de 'donnees' + for cle in donnees: + self[cle] = donnees[cle] + + def __repr__(self): + """Représentation de notre objet. C'est cette chaîne qui sera affichée + quand on saisit directement le dictionnaire dans l'interpréteur, ou en + utilisant la fonction 'repr'""" + + chaine = "{" + premier_passage = True + for cle, valeur in self.items(): + if not premier_passage: + chaine += ", " # On ajoute la virgule comme séparateur + else: + premier_passage = False + chaine += repr(cle) + ": " + repr(valeur) + chaine += "}" + return chaine + + def __str__(self): + """Fonction appelée quand on souhaite afficher le dictionnaire grâce + à la fonction 'print' ou le convertir en chaîne grâce au constructeur + 'str'. On redirige sur __repr__""" + + return repr(self) + + def __len__(self): + """Renvoie la taille du dictionnaire""" + return len(self._cles) + + def __contains__(self, cle): + """Renvoie True si la clé est dans la liste des clés, False sinon""" + return cle in self._cles + + def __getitem__(self, cle): + """Renvoie la valeur correspondant à la clé si elle existe, lève + une exception KeyError sinon""" + + if cle not in self._cles: + raise KeyError( \ + "La clé {0} ne se trouve pas dans le dictionnaire".format( \ + cle)) + else: + indice = self._cles.index(cle) + return self._valeurs[indice] + + def __setitem__(self, cle, valeur): + """Méthode spéciale appelée quand on cherche à modifier une clé + présente dans le dictionnaire. Si la clé n'est pas présente, on l'ajoute + à la fin du dictionnaire""" + + if cle in self._cles: + indice = self._cles.index(cle) + self._valeurs[indice] = valeur + else: + self._cles.append(cle) + self._valeurs.append(valeur) + + def __delitem__(self, cle): + """Méthode appelée quand on souhaite supprimer une clé""" + if cle not in self._cles: + raise KeyError( \ + "La clé {0} ne se trouve pas dans le dictionnaire".format( \ + cle)) + else: + indice = self._cles.index(cle) + del self._cles[indice] + del self._valeurs[indice] + + def __iter__(self): + """Méthode de parcours de l'objet. On renvoie l'itérateur des clés""" + return iter(self._cles) + + def __add__(self, autre_objet): + """On renvoie un nouveau dictionnaire contenant les deux + dictionnaires mis bout à bout (d'abord self puis autre_objet)""" + + if type(autre_objet) is not type(self): + raise TypeError( \ + "Impossible de concaténer {0} et {1}".format( \ + type(self), type(autre_objet))) + else: + nouveau = DictionnaireOrdonne() + + # On commence par copier self dans le dictionnaire + for cle, valeur in self.items(): + nouveau[cle] = valeur + + # On copie ensuite autre_objet + for cle, valeur in autre_objet.items(): + nouveau[cle] = valeur + return nouveau + + def items(self): + """Renvoie un générateur contenant les couples (cle, valeur)""" + for i, cle in enumerate(self._cles): + valeur = self._valeurs[i] + yield (cle, valeur) + + def keys(self): + """Cette méthode renvoie la liste des clés""" + return list(self._cles) + + def values(self): + """Cette méthode renvoie la liste des valeurs""" + return list(self._valeurs) + + def reverse(self): + """Inversion du dictionnaire""" + # On crée deux listes vides qui contiendront le nouvel ordre des clés + # et valeurs + cles = [] + valeurs = [] + for cle, valeur in self.items(): + # On ajoute les clés et valeurs au début de la liste + cles.insert(0, cle) + valeurs.insert(0, valeur) + # On met ensuite à jour nos listes + self._cles = cles + self._valeurs = valeurs + + def sort(self): + """Méthode permettant de trier le dictionnaire en fonction de ses clés""" + # On trie les clés + cles_triees = sorted(self._cles) + # On crée une liste de valeurs, encore vide + valeurs = [] + # On parcourt ensuite la liste des clés triées + for cle in cles_triees: + valeur = self[cle] + valeurs.append(valeur) + # Enfin, on met à jour notre liste de clés et de valeurs + self._cles = cles_triees + self._valeurs = valeurs + + +if __name__ == "__main__": + """ Active les doctests """ + + import doctest + doctest.testmod() diff --git a/package/dico_ord.py b/package/dico_ord.py new file mode 100644 index 0000000..6d633dd --- /dev/null +++ b/package/dico_ord.py @@ -0,0 +1,281 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Author: freezed 2018-01-25 +Version: 0.1 +Licence: `GNU GPL v3`: http://www.gnu.org/licenses/ +""" + + +class DictionnaireOrdonne: + + """ + Dictionnaire ordonne + ==================== + + Objet ressemblant a un dict, avec des capacitees de tri. + + Les cles et valeurs se trouvant dans des listes de meme + taille, il suffira de prendre l'indice dans une liste pour + savoir quel objet lui correspond dans l'autre. Par exemple, + la cle d'indice 0 est couplee avec la valeur d'indice 0. + + :Example: + >>> fruits = DictionnaireOrdonne() + >>> fruits + {} + + >>> fruits["pomme"] = 52 + >>> fruits["poire"] = 34 + >>> fruits["prune"] = 128 + >>> fruits["melon"] = 15 + >>> fruits + {'pomme': 52, 'poire': 34, 'prune': 128, 'melon': 15} + + >>> fruits.sort() + >>> print(fruits) + {'melon': 15, 'poire': 34, 'pomme': 52, 'prune': 128} + + >>> legumes = DictionnaireOrdonne(carotte = 26, haricot = 48) + + # Test possible seulement avec python 3.6, + # voir: www.python.org/dev/peps/pep-0468/ + #>>> print(legumes) + #{'carotte': 26, 'haricot': 48} + + >>> len(legumes) + 2 + + >>> legumes.reverse() + + >>> fruits = fruits + legumes + >>> fruits + {'melon': 15, 'poire': 34, 'pomme': 52, 'prune': 128, 'haricot': 48, 'carotte': 26} + + >>> del fruits['haricot'] + >>> del fruits['betterave'] + ValueError: «'betterave' is not in list» + + >>> 'haricot' in fruits + False + + >>> 'pomme' in fruits + True + + >>> legumes['haricot'] + 48 + >>> fruits['betterave'] + ValueError: «'betterave' is not in list» + + >>> for cle in legumes: + ... print(cle) + ... + haricot + carotte + + >>> fruits.keys() + ['melon', 'poire', 'pomme', 'prune', 'carotte'] + + >>> legumes.keys() + ['haricot', 'carotte'] + + >>> fruits.values() + [15, 34, 52, 128, 26] + + >>> legumes.values() + [48, 26] + + >>> for nom, qtt in legumes.items(): + ... print("{0} ({1})".format(nom, qtt)) + ... + haricot (48) + carotte (26) + + >>> liste = [0,1,2,3] + >>> tentative1 = DictionnaireOrdonne(liste) + Un dict() est attendu en argument! + + >>> dico_vide = {} + >>> tentative2 = DictionnaireOrdonne(dico_vide) + >>> tentative2 + {} + + >>> mots = {'olive': 51, 'identite': 43, 'mercredi': 25, 'prout': 218, 'assiette': 8, 'truc': 26} + >>> mots_ordonne = DictionnaireOrdonne(mots) + >>> mots_ordonne.sort() + >>> mots_ordonne + {'assiette': 8, 'mercredi': 25, 'truc': 26, 'identite': 43, 'olive': 51, 'prout': 218} + """ + + def __init__(self, filled_dict={}, **kwargs): + """ + Peu prendre aucun parametre ou: + - un dictionnaire 'filled_dict' en 1er argument + - des valeurs nommees dans 'kwargs' + """ + # Creation des attributs qui stokeront les cles et valeurs + self._keys_list = list() + self._values_list = list() + + # Si 'filled_dict' est un dict() non vide, ajout du contenu + if type(filled_dict) not in (dict, DictionnaireOrdonne): + #raise TypeError("Un dict() est attendu en argument!") + print("Un dict() est attendu en argument!") + else: + for key, val in filled_dict.items(): + self._keys_list.append(key) + self._values_list.append(val) + + # Si les kwargs ne sont pas vide, ajout du contenu + if len(kwargs) != 0: + for key, val in kwargs.items(): + self._keys_list.append(key) + self._values_list.append(val) + + def __add__(self, other_dict_ord): + """ + On doit pouvoir ajouter deux dictionnaires ordonnes + (dico1 + dico2) ; les cles et valeurs du second dictionnaire + sont ajoutees au premier. + """ + i = 0 + while i < len(other_dict_ord): + self._keys_list.append(other_dict_ord._keys_list[i]) + self._values_list.append(other_dict_ord._values_list[i]) + i += 1 + + return self + + def __contains__(self, key_to_find): + """ Cherche une cle dans notre objet (cle in dictionnaire) """ + return key_to_find in self._keys_list + + def __delitem__(self, key_to_del): + """ Acces avec crochets pour suppression (del objet[cle]) """ + try: + index_to_del = self._keys_list.index(key_to_del) + except ValueError as except_detail: + print("ValueError: «{}»".format(except_detail)) + else: + del self._keys_list[index_to_del] + del self._values_list[index_to_del] + + def __iter__(self): + """Parcours de l'objet, renvoi l'iterateur des cles""" + return iter(self._keys_list) + + def __getitem__(self, key_to_get): + """ Acces aux crochets pour recuperer une valeur (objet[cle]) """ + try: + find_key = self._keys_list.index(key_to_get) + except ValueError as except_detail: + print("ValueError: «{}»".format(except_detail)) + else: + print(self._values_list[find_key]) + + def __len__(self): + """ Retourne la taille de l'objet grace a la fonction len """ + return len(self._keys_list) + + def __repr__(self): + """ + Affiche l'objet dans l'interpreteur ou grâce a la fonction + print: ({cle1: valeur1, cle2: valeur2, …}). + """ + # contiendra le txt a afficher + object_repr = list() + + # Si l'objet n'est pas vide + if len(self._keys_list) != 0: + for i in range(0, len(self._keys_list)): + object_repr.append("'{}': {}".format(self._keys_list[i], self._values_list[i])) + + return "{0}{1}{2}".format( + "{", + ", ".join(object_repr), + "}" + ) + + def __setitem__(self, cle, valeur): + """ + Acces avec crochets pour modif (objet[cle] = valeur). Si la cle + existe on ecrase l'ancienne valeur, sinon on ajoute le couple + cle-valeur a la fin + """ + try: + index = self._keys_list.index(cle) + self._keys_list[index] = cle + self._values_list[index] = valeur + except ValueError: + self._keys_list.append(cle) + self._values_list.append(valeur) + + def __str__(self): + """ + Methode pour afficher le dictionnaire avec «print()» ou pour + le convertir en chaine grâce aec «str()». Redirige sur __repr__ + """ + return repr(self) + + def keys(self): + """ + La methode keys() (renvoyant la liste des cles) doit etre + mises en œuvre. Le type de retour de ces methodes est laisse + a votre initiative : il peut s'agir d'iterateurs ou de + generateurs (tant qu'on peut les parcourir) + """ + return list(self._keys_list) + + def sort(self, reverse=False): + """ + L'objet doit definir les methodes sort pour le trier et reverse + pour l'inverser. Le tri de l'objet doit se faire en fonction + des cles + """ + # Peut etre un peu overkill… voir methode dans la correction + + # pour trier on stocke les couples de cle & valeur sous forme + # de tuple dans une liste temporaire + liste_temporaire = list() + + if len(self._keys_list) != 0: # Seulement si il y a des donnees + for i in range(0, len(self._keys_list)): # on parcour chaque entee + liste_temporaire.append((self._keys_list[i], self._values_list[i])) + + # Tri des tuples par la valeur par une comprension de liste + liste_permute = [(val, cle) for cle, val in liste_temporaire] + liste_triee = [(cle, val) for val, cle in sorted(liste_permute, reverse=reverse)] + + # On range les donnees tries dans attributs de l'objet + self._keys_list = [cle for cle, val in liste_triee] + self._values_list = [val for cle, val in liste_triee] + + def reverse(self): + """ + L'objet doit definir les methodes sort pour le trier et reverse + pour l'inverser. Le tri de l'objet doit se faire en fonction + des cles + """ + return self.sort(reverse=True) + + def items(self): + """Renvoi un generateur contenant les couples (cle, valeur)""" + for key, val in enumerate(self._keys_list): + yield (val, self._values_list[key]) + + def values(self): + """ + La methode values() (renvoi la liste des valeurs) doit etre + mises en œuvre. Le type de retour de ces methodes est laisse + a votre initiative : il peut s'agir d'iterateurs ou de + generateurs (tant qu'on peut les parcourir) + """ + return list(self._values_list) + + +if __name__ == "__main__": + """ Active les doctests """ + + import doctest + doctest.testmod()