2018-01-31 10:33:19 +00:00
|
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
|
|
"""
|
2018-02-02 16:01:25 +00:00
|
|
|
|
Author: freezed <freezed@users.noreply.github.com> 2018-01-25
|
|
|
|
|
Version: 0.1
|
|
|
|
|
Licence: `GNU GPL v3`: http://www.gnu.org/licenses/
|
2018-01-31 10:33:19 +00:00
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DictionnaireOrdonne:
|
|
|
|
|
|
|
|
|
|
"""
|
2018-02-02 16:01:25 +00:00
|
|
|
|
Dictionnaire ordonne
|
|
|
|
|
====================
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
2018-02-02 16:01:25 +00:00
|
|
|
|
Objet ressemblant a un dict, avec des capacitees de tri.
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
2018-02-02 16:01:25 +00:00
|
|
|
|
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.
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
2018-02-02 16:01:25 +00:00
|
|
|
|
:Example:
|
|
|
|
|
>>> fruits = DictionnaireOrdonne()
|
|
|
|
|
>>> fruits
|
|
|
|
|
{}
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
2018-02-02 16:01:25 +00:00
|
|
|
|
>>> fruits["pomme"] = 52
|
|
|
|
|
>>> fruits["poire"] = 34
|
|
|
|
|
>>> fruits["prune"] = 128
|
|
|
|
|
>>> fruits["melon"] = 15
|
|
|
|
|
>>> fruits
|
|
|
|
|
{'pomme': 52, 'poire': 34, 'prune': 128, 'melon': 15}
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
2018-02-02 16:01:25 +00:00
|
|
|
|
>>> fruits.sort()
|
|
|
|
|
>>> print(fruits)
|
|
|
|
|
{'melon': 15, 'poire': 34, 'pomme': 52, 'prune': 128}
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
2018-02-02 16:01:25 +00:00
|
|
|
|
>>> legumes = DictionnaireOrdonne(carotte = 26, haricot = 48)
|
2018-02-02 11:21:16 +00:00
|
|
|
|
|
2018-02-02 16:01:25 +00:00
|
|
|
|
# Test possible seulement avec python 3.6,
|
|
|
|
|
# voir: www.python.org/dev/peps/pep-0468/
|
|
|
|
|
#>>> print(legumes)
|
|
|
|
|
#{'carotte': 26, 'haricot': 48}
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
2018-02-02 16:01:25 +00:00
|
|
|
|
>>> len(legumes)
|
|
|
|
|
2
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
2018-02-02 16:01:25 +00:00
|
|
|
|
>>> legumes.reverse()
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
2018-02-02 16:01:25 +00:00
|
|
|
|
>>> fruits = fruits + legumes
|
|
|
|
|
>>> fruits
|
|
|
|
|
{'melon': 15, 'poire': 34, 'pomme': 52, 'prune': 128, 'haricot': 48, 'carotte': 26}
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
2018-02-02 16:01:25 +00:00
|
|
|
|
>>> del fruits['haricot']
|
|
|
|
|
>>> del fruits['betterave']
|
|
|
|
|
ValueError: «'betterave' is not in list»
|
2018-02-02 14:18:38 +00:00
|
|
|
|
|
2018-02-02 16:01:25 +00:00
|
|
|
|
>>> 'haricot' in fruits
|
|
|
|
|
False
|
2018-02-02 15:38:18 +00:00
|
|
|
|
|
2018-02-02 16:01:25 +00:00
|
|
|
|
>>> 'pomme' in fruits
|
|
|
|
|
True
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
2018-02-02 16:09:47 +00:00
|
|
|
|
>>> legumes['haricot']
|
|
|
|
|
48
|
|
|
|
|
>>> fruits['betterave']
|
2018-02-05 13:36:17 +00:00
|
|
|
|
ValueError: «'betterave' is not in list»
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
2018-02-02 22:17:31 +00:00
|
|
|
|
>>> for cle in legumes:
|
|
|
|
|
... print(cle)
|
|
|
|
|
...
|
|
|
|
|
haricot
|
|
|
|
|
carotte
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
2018-02-04 10:30:00 +00:00
|
|
|
|
>>> fruits.keys()
|
|
|
|
|
['melon', 'poire', 'pomme', 'prune', 'carotte']
|
|
|
|
|
|
|
|
|
|
>>> legumes.keys()
|
|
|
|
|
['haricot', 'carotte']
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
2018-02-04 10:36:16 +00:00
|
|
|
|
>>> fruits.values()
|
|
|
|
|
[15, 34, 52, 128, 26]
|
|
|
|
|
|
|
|
|
|
>>> legumes.values()
|
|
|
|
|
[48, 26]
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
2018-02-05 14:23:05 +00:00
|
|
|
|
>>> for nom, qtt in legumes.items():
|
|
|
|
|
... print("{0} ({1})".format(nom, qtt))
|
|
|
|
|
...
|
|
|
|
|
haricot (48)
|
|
|
|
|
carotte (26)
|
2018-02-04 12:10:45 +00:00
|
|
|
|
|
2018-02-05 15:04:48 +00:00
|
|
|
|
>>> 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}
|
2018-01-31 10:33:19 +00:00
|
|
|
|
"""
|
|
|
|
|
|
2018-02-05 15:04:48 +00:00
|
|
|
|
def __init__(self, filled_dict={}, **kwargs):
|
2018-01-31 10:33:19 +00:00
|
|
|
|
"""
|
2018-02-05 15:04:48 +00:00
|
|
|
|
Peu prendre aucun parametre ou:
|
|
|
|
|
- un dictionnaire 'filled_dict' en 1er argument
|
|
|
|
|
- des valeurs nommees dans 'kwargs'
|
2018-01-31 10:33:19 +00:00
|
|
|
|
"""
|
2018-02-02 16:01:25 +00:00
|
|
|
|
# Creation des attributs qui stokeront les cles et valeurs
|
2018-02-05 13:26:31 +00:00
|
|
|
|
self._keys_list = list()
|
|
|
|
|
self._values_list = list()
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
2018-02-05 15:04:48 +00:00
|
|
|
|
# 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)
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
2018-02-02 16:01:25 +00:00
|
|
|
|
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):
|
2018-02-05 13:26:31 +00:00
|
|
|
|
self._keys_list.append(other_dict_ord._keys_list[i])
|
|
|
|
|
self._values_list.append(other_dict_ord._values_list[i])
|
2018-02-02 16:01:25 +00:00
|
|
|
|
i += 1
|
|
|
|
|
|
|
|
|
|
return self
|
|
|
|
|
|
2018-02-05 13:31:45 +00:00
|
|
|
|
def __contains__(self, key_to_find):
|
2018-02-02 16:01:25 +00:00
|
|
|
|
""" Cherche une cle dans notre objet (cle in dictionnaire) """
|
2018-02-05 13:43:42 +00:00
|
|
|
|
return key_to_find in self._keys_list
|
2018-02-02 16:01:25 +00:00
|
|
|
|
|
2018-02-05 13:31:45 +00:00
|
|
|
|
def __delitem__(self, key_to_del):
|
2018-02-02 16:01:25 +00:00
|
|
|
|
""" Acces avec crochets pour suppression (del objet[cle]) """
|
|
|
|
|
try:
|
2018-02-05 13:31:45 +00:00
|
|
|
|
index_to_del = self._keys_list.index(key_to_del)
|
2018-02-02 16:01:25 +00:00
|
|
|
|
except ValueError as except_detail:
|
|
|
|
|
print("ValueError: «{}»".format(except_detail))
|
|
|
|
|
else:
|
2018-02-05 13:26:31 +00:00
|
|
|
|
del self._keys_list[index_to_del]
|
|
|
|
|
del self._values_list[index_to_del]
|
2018-02-02 16:01:25 +00:00
|
|
|
|
|
2018-02-02 22:17:31 +00:00
|
|
|
|
def __iter__(self):
|
2018-02-05 14:23:05 +00:00
|
|
|
|
"""Parcours de l'objet, renvoi l'iterateur des cles"""
|
|
|
|
|
return iter(self._keys_list)
|
2018-02-02 22:17:31 +00:00
|
|
|
|
|
2018-02-05 13:31:45 +00:00
|
|
|
|
def __getitem__(self, key_to_get):
|
2018-02-02 16:09:47 +00:00
|
|
|
|
""" Acces aux crochets pour recuperer une valeur (objet[cle]) """
|
|
|
|
|
try:
|
2018-02-05 13:31:45 +00:00
|
|
|
|
find_key = self._keys_list.index(key_to_get)
|
2018-02-05 13:36:17 +00:00
|
|
|
|
except ValueError as except_detail:
|
|
|
|
|
print("ValueError: «{}»".format(except_detail))
|
2018-02-02 16:09:47 +00:00
|
|
|
|
else:
|
2018-02-05 13:26:31 +00:00
|
|
|
|
print(self._values_list[find_key])
|
2018-02-02 16:09:47 +00:00
|
|
|
|
|
2018-02-02 16:01:25 +00:00
|
|
|
|
def __len__(self):
|
|
|
|
|
""" Retourne la taille de l'objet grace a la fonction len """
|
2018-02-05 13:26:31 +00:00
|
|
|
|
return len(self._keys_list)
|
2018-02-02 16:01:25 +00:00
|
|
|
|
|
2018-01-31 10:33:19 +00:00
|
|
|
|
def __repr__(self):
|
|
|
|
|
"""
|
|
|
|
|
Affiche l'objet dans l'interpreteur ou grâce a la fonction
|
2018-02-02 16:01:25 +00:00
|
|
|
|
print: ({cle1: valeur1, cle2: valeur2, …}).
|
2018-01-31 10:33:19 +00:00
|
|
|
|
"""
|
2018-02-02 16:01:25 +00:00
|
|
|
|
# contiendra le txt a afficher
|
|
|
|
|
object_repr = list()
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
2018-02-02 16:01:25 +00:00
|
|
|
|
# Si l'objet n'est pas vide
|
2018-02-05 13:26:31 +00:00
|
|
|
|
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]))
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
|
|
|
|
return "{0}{1}{2}".format(
|
|
|
|
|
"{",
|
2018-02-02 16:01:25 +00:00
|
|
|
|
", ".join(object_repr),
|
2018-01-31 10:33:19 +00:00
|
|
|
|
"}"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def __setitem__(self, cle, valeur):
|
|
|
|
|
"""
|
2018-02-02 16:01:25 +00:00
|
|
|
|
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
|
2018-01-31 10:33:19 +00:00
|
|
|
|
"""
|
|
|
|
|
try:
|
2018-02-05 13:26:31 +00:00
|
|
|
|
index = self._keys_list.index(cle)
|
|
|
|
|
self._keys_list[index] = cle
|
|
|
|
|
self._values_list[index] = valeur
|
2018-01-31 10:33:19 +00:00
|
|
|
|
except ValueError:
|
2018-02-05 13:26:31 +00:00
|
|
|
|
self._keys_list.append(cle)
|
|
|
|
|
self._values_list.append(valeur)
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
2018-02-05 11:21:44 +00:00
|
|
|
|
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)
|
2018-02-05 10:22:52 +00:00
|
|
|
|
|
2018-02-04 10:30:00 +00:00
|
|
|
|
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)
|
|
|
|
|
"""
|
2018-02-05 13:37:43 +00:00
|
|
|
|
return list(self._keys_list)
|
2018-02-04 10:30:00 +00:00
|
|
|
|
|
2018-01-31 10:33:19 +00:00
|
|
|
|
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
|
|
|
|
|
"""
|
2018-02-05 10:22:52 +00:00
|
|
|
|
# Peut etre un peu overkill… voir methode dans la correction
|
|
|
|
|
|
2018-01-31 10:33:19 +00:00
|
|
|
|
# pour trier on stocke les couples de cle & valeur sous forme
|
|
|
|
|
# de tuple dans une liste temporaire
|
|
|
|
|
liste_temporaire = list()
|
|
|
|
|
|
2018-02-05 13:26:31 +00:00
|
|
|
|
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]))
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
|
|
|
|
# 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
|
2018-02-05 13:26:31 +00:00
|
|
|
|
self._keys_list = [cle for cle, val in liste_triee]
|
|
|
|
|
self._values_list = [val for cle, val in liste_triee]
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
2018-02-02 16:01:25 +00:00
|
|
|
|
def reverse(self):
|
2018-02-02 14:00:57 +00:00
|
|
|
|
"""
|
2018-02-02 16:01:25 +00:00
|
|
|
|
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
|
2018-02-02 14:00:57 +00:00
|
|
|
|
"""
|
2018-02-02 16:01:25 +00:00
|
|
|
|
return self.sort(reverse=True)
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
2018-02-05 09:18:56 +00:00
|
|
|
|
def items(self):
|
2018-02-05 14:23:05 +00:00
|
|
|
|
"""Renvoi un generateur contenant les couples (cle, valeur)"""
|
|
|
|
|
for key, val in enumerate(self._keys_list):
|
|
|
|
|
yield (val, self._values_list[key])
|
2018-02-04 10:36:16 +00:00
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
"""
|
2018-02-05 13:37:43 +00:00
|
|
|
|
return list(self._values_list)
|
2018-01-31 10:33:19 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
""" Active les doctests """
|
|
|
|
|
|
|
|
|
|
import doctest
|
|
|
|
|
doctest.testmod()
|