[Python 3] Méthodes de tri

ARTICLE EN COURS DE CONSTRUCTION

### 2 - TRI - ###

### 2.1 TRI : tuple
aa = (8, 4, 6, 1, 9, 5, 2, 7, 0, 3)
### 2.1.1 TRI : tuple : sorted()
print("### 2.1.1 TRI : tuple : sorted()")
sorted(aa)
print(aa)
print(sorted(aa))
print()

### 2.2 TRI : list à une dimension
aa = [8, 4, 6, 1, 9, 5, 2, 7, 0, 3]
### 2.2.1 TRI : list à une dimension : sorted()
print("### 2.2.1 TRI : list à une dimension : sorted()")
sorted(aa)
print(aa)
print(sorted(aa))
print()

### 2.2.2 TRI : list à une dimension : sort()
print("### 2.2.2 TRI : list à une dimension : sort()")
aa.sort()
print(aa)
print()

### 2.3 TRI : list à plusieurs dimensions
aa = [
("h", "J", 2),
("j", "I", 8),
("a", "G", 4),
("g", "H", 3),
("i", "E", 6),
("b", "D", 5),
("c", "B", 0),
("d", "F", 7),
("f", "C", 1),
("e", "A", 9)
]
### 2.3.1 TRI : list à plusieurs dimensions : sorted()
print("### 2.3 TRI : list à plusieurs dimensions : sorted()")
sorted(aa)
print(aa)
print(sorted(aa))
print()

### 2.3.2 TRI : list à plusieurs dimensions : lambda
print("### 2.3 TRI : list à plusieurs dimensions : lambda")
xx = sorted(aa, key=lambda x: x[0])
print(*xx)
yy = sorted(aa, key=lambda x: x[1])
print(*yy)
zz = sorted(aa, key=lambda x: x[2])
print(*zz)
print()

### 2.3.3 TRI : list à plusieurs dimensions : itemgetter
aa = [
("abricot ", "catégorie 1 ", "prix 1"),
("pomme ", "catégorie 1 ", "prix 1"),
("orange ", "catégorie 1 ", "prix 1"),
("orange ", "catégorie 2 ", "prix 3"),
("raisin ", "catégorie 1 ", "prix 3"),
("abricot ", "catégorie 2 ", "prix 2"),
("pomme ", "catégorie 1 ", "prix 1"),
("abricot ", "catégorie 2 ", "prix 2"),
("pomme ", "catégorie 1 ", "prix 1"),
("orange ", "catégorie 2 ", "prix 2")
]
from operator import itemgetter as ig
print("### 2.3 TRI : list à plusieurs dimensions : itemgetter")
zz = sorted(aa, key=ig(0,1,2))
print(*zz)
zz = sorted(aa, key=ig(1,0,2))

for i, j, k in zz:
print(i, j, k)

print()

### 2.4 TRI : dict
dico = {"Alain": 2, "Bernard": 3, "Christian": 4, "Dominique": 1}

### 2.4.1 TRI : dict : lambda
print("### 2.4.1 TRI : dict : lambda")
aa = dico.items()

zz = sorted(aa, key=lambda x: x[0])
print(*zz)
zz = sorted(aa, key=lambda x: x[1])
print(*zz)
print()

### 2.4.2 TRI : dict : itemgetter
from operator import itemgetter as ig
print("### 2.4.2 TRI : dict : itemgetter")

aa = dico.items()

zz = sorted(aa, key=ig(0))
print(*zz)
zz = sorted(aa, key=ig(1))
print(*zz)
print()

### 2.5 TRI : class
### 2.5.1 TRI : class : list (ou tuple) : attrgetter
class Fruits:
def __init__(self, aa, bb):
self.prod = aa
self.prix = bb

def __repr__(self):
return "\n{} : {}€".format(self.prod, self.prix)

fruits = [
Fruits("poires ", 3),
Fruits("pommes ", 2),
Fruits("oranges", 2),
Fruits("cerises", 4),
Fruits("abricot", 2)
]

from operator import attrgetter as ag
print("### 2.5.1 TRI : class : list (ou tuple) : attrgetter")
zz = sorted(fruits, key=ag("prod", "prix"))
print(*zz)

zz = sorted(fruits, key=ag("prix", "prod"))
print(*zz)
print()

### 2.5.2 TRI : class : dict : attrgetter
dico = {}
dico["poires"] = Fruits("poires ", 3)
dico["pommes"] = Fruits("pommes ", 2)
dico["oranges"] = Fruits("oranges ", 2)
dico["cerises"] = Fruits("cerises ", 4)
dico["abricots"] = Fruits("abricots", 2)

from operator import attrgetter as ag
print("### 2.5.2 TRI : class : dict : attrgetter")

zz = sorted(dico.values(), key=ag("prod", "prix"))
print(*zz)
zz = sorted(dico.values(), key=ag("prix", "prod"))
print(*zz)
Publicités

[Python 3] Trier un « Dictionnaire »

Dans de nombreux langages informatiques, on retrouve le « Dictionnaire », cette variable un petit peu particulière qui regroupe l’association d’un ensemble de « clés » à leur « valeur », comme un dictionnaire est le regroupement d’un ensemble de mots associés à leur définition.

Je ne m’étendrai pas, ici, sur le fonctionnement du dictionnaire; je rappellerai néanmoins que dans un dictionnaire, chaque clé (le mot) est unique (mais plusieurs clés peuvent avoir la même valeur).

En Python, on remarquera que l’affichage du contenu d’un dictionnaire est aléatoire; ainsi, si j’établis mon dictionnaire dico de la façon suivante et que j’en demande l’affichage par une fonction print()

dico = {"zéro" : 0, "un" : 1, "deux" : 2, "trois" : 3, "quatre" : 4, "cinq" : 5}
print(dico)

Résultat : {‘un’: 1, ‘quatre’: 4, ‘deux’: 2, ‘zéro’: 0, ‘cinq’: 5, ‘trois’: 3}

je constate que, même si l’affichage n’est pas particulièrement attrayant, les éléments qui composent notre dictionnaire sont présentés de façon erratique.

N’ayant pas la possibilité de modifier l’ordre d’affichage dans un dictionnaire, nous allons contourner ce problème en enregistrant l’ensemble de notre dictionnaire dans une variable que nous appellerons ici mavar

mavar = dico.items()

Notons simplement que pour réussir notre opération, nous devons faire appel à la méthode items().
Ensuite, nous appliquons la méthode sorted() pour effectuer le tri et l’enregistrons dans une variable que nous appelons montri

montri = sorted(mavar, key=lambda x: x[1])

La méthode sorted() appelle tout d’abord l’objet que nous souhaitons trier, à savoir la variable mavar dans laquelle nous avons enregistré l’ensemble des binômes contenus dans notre dictionnaire.

Nous choisissons ensuite, avec la suite key=lambda x: x[1], la « clé » key de notre tri (à ne pas confondre avec les clés du dictionnaire), qui va définir le paramètre de tri (tri par clés du dictionnaire – zéro, un, deux etc… – auquel cas la valeur entre crochets sera x[0], ou par valeurs – 0, 1, 2 – avec x[1]).

A noter que si nous voulions notre affichage dans l’ordre descendant, nous aurions rajouté à notre méthode sorted() la commande reverse=True, comme ceci

montri = sorted(mavar, key=lambda x: x[1], reverse=True)

Pour info : il existe d’autres méthodes pour faire un tri en Python, notamment en faisant appel à la commande itemgetter de la bibliothèque operator.

Il ne nous reste plus qu’à afficher le résultat de notre tri, avec une « liste en intention », par exemple, alternative intéressante à la traditionnelle boucle en for

[print(j, i) for i, j in montri]

Quelques explications concernant cette ligne : rappelons que la variable montri est composée de binômes :
zéro, 0
un, 1
deux, 2…
i et j vont respectivement venir extraire les clés (zéro, un, deux, trois…) et les valeurs (0, 1, 2..).
Notre ligne de code demande donc d’afficher successivement chaque binôme j, i (print(j, i) nous avons inversé l’ordre d’affichage) par l’intermédiaire d’une boucle (for i, j) contenu dans notre objet montri.

Voici le code dans sa totalité :

dico = {"zéro" : 0, "un" : 1, "deux" : 2, "trois" : 3, "quatre" : 4, "cinq" : 5}
mavar = dico.items()
montri = sorted(mavar, key=lambda x: x[1])
[print(j, i) for i, j in montri]


0 zéro
1 un
2 deux
3 trois
4 quatre
5 cinq

[VBA] La variable « Dictionnaire »

Outre sa rapidité, le « Dictionnaire » est une variable particulière qui a pour fonction de gérer les doublons.
Il intervient dans une grande variété de cas de figures et fait partie des outils indispensables à maîtriser lorsqu’on travaille avec des bases de données.
Le dictionnaire est une variable qui va enregistrer une série de « clés » (Key) uniques; chaque clé composant le dictionnaire est accompagnée d’un « élément » (Item), dont la valeur est modifiable.

Dans l’exemple ci-dessous, qui va préciser l’utilité et le fonctionnement du dictionnaire, nous souhaitons calculer le montant total des factures pour chaque client, sachant que la première facture donne automatiquement lieu à une réduction de 10%.

Dictionnary

Option Base 1
Sub test()
'Dans la fenêtre VBA, sélectionner Outils, Références et cocher Microsoft Scripting Runtime
Dim Dico As Object
Dim c As Byte
Dim ii As Variant, jj As Variant
Set Dico = CreateObject("scripting.dictionary")

c = 2
Do Until IsEmpty(Cells(c, 1))
If Not Dico.exists(Cells(c, 1).Value) Then
    Dico(Cells(c, 1).Value) = 0.9 * Cells(c, 3)
Else
    Dico(Cells(c, 1).Value) = Dico(Cells(c, 1).Value) + Cells(c, 3)
End If
c = c + 1
Loop

Range("E1").Resize(Dico.Count, 1) = Application.Transpose(Dico.keys)
Range("F1").Resize(Dico.Count, 1) = Application.Transpose(Dico.items)

Range("G1") = Application.Index(Dico.keys, 3)
Range("H1") = Application.Index(Dico.items, 3)

ii = Dico.keys
jj = Dico.items

Range("I1") = ii(3)
Range("J1") = jj(3)

Set Dico = Nothing: Erase ii: Erase jj
End Sub

Explications

Nous allons, en premier lieu, nous rendre dans la fenêtre VBA, sélectionner Outils, Références et cocher Microsoft Scripting Runtime : nous venons d’accéder à une « librairie » qui nous permet d’avoir des fonctionnalités supplémentaires.

La première étape consiste à créer un « objet » : nous commençons par déclarer la variable que nous nommons Dico Dim Dico As Object; nous créons, ensuite, l’objet Dico Set Dico = CreateObject("scripting.filesystemobject").

A partir d’une boucle classique, nous allons ensuite enregistrer chaque nouveau client de la colonne A dans le dictionnaire. la condition If Not Dico.exists(Cells(c, 1).Value) Then vérifie si la valeur de notre cellule existe déjà dans le dictionnaire ou pas. Son utilisation est très simple; le nom de l’objet créé (Dico) est suivi de la commande .exists et de la valeur à vérifier (Cells(c, 1).Value). Il est préférable de préciser que l’on cherche à enregistrer la valeur (Value) de la cellule (Cells(c,1)) afin que le dictionnaire ne la confonde pas avec la plage de la même cellule.
Cette condition que nous venons de mettre en place n’est, en général, pas nécessaire mais elle est utile dans notre cas de figure.

La commande suivante mérite quelques explications : Dico(Cells(c, 1).Value) = 0.9 * Cells(c, 3). Cela veut dire que si la valeur de notre cellule en colonne A apprait pour la première fois (donc la condition évoquée par la ligne de code précédente) alors la valeur de la cellule de la colonne C correspondante doit être enregistrée à 90% de sa valeur (0.9 * Cells(c, 3)).
Nous devons maintenant comprendre les informations que nous avons de part et d’autre de notre signe =
La partie de gauche Dico(Cells(c, 1).Value) est la clé.
La clé est une valeur unique (pour la première ligne de notre tableau, notre clé = CLient 1), c’est à dire qui ne sera enregistrée qu’une seule fois et qui fait office de « case variable » dans laquelle nous allons enregistrer la valeur de la facture en colonne C -10%.
Autrement dit, notre variable Client 1 a une valeur de 0.9 * 100 donc Client 1 (Key) = 90 (Item)
Pareil, pour la deuxième ligne de notre tableau : Client 15 (Key) = 99 (Item)
etc…
Le principe est exactement le même que celui ou c=c+1 : à gauche, la variable et à droite, le calcul reprenant l’ancienne valeur de cette même variable et l’actualisant; c’est ce qui se passe lorsque notre condition n’est plus vérifiée, autrement dit si notre Key existe déjà, dans la ligne suivante : Dico(Cells(c, 1).Value) = Dico(Cells(c, 1).Value) + Cells(c, 3).

Reprenons l’exemple de notre premier client : Client 1 = 90
Lorsque la boucle va, à nouveau, rencontrer la valeur Client 1 dans notre tableau, en ligne N° 15, alors Client 1 = Client 1 + 230, autrement dit Client 1 = 90 + 230, donc Client 1 (Key) = 320 (Item).

Nous transposons ensuite les résultats de notre dictionnaire dans sur la feuille Excel.
Range("E1").Resize(Dico.Count, 1) = Application.Transpose(Dico.keys)
Range("F1").Resize(Dico.Count, 1) = Application.Transpose(Dico.items)

La transposition se fait ici en deux étapes, la première concernant les Keys et la seconde, les Item.
Voir l’article suivant pour de plus amples détails concernant la transposition.
La seule différence avec une transposition de variable tableau, est que la commande Ubound est remplacée par Dico.Count qui a exactement la même fonction et qui compte le nombre d’éléments que contient le dictionnaire.

On peut également extraire une valeur unique, Key ou Item : nous disposons de deux outils pour cela.
La première consiste à identifier la valeur voulue à partir de son index, c’est à dire son rang dans la série d’éléments de même nature à laquelle elle appartient.
Range("G1") = Application.Index(Dico.keys, 3)
Range("H1") = Application.Index(Dico.items, 3)

La seconde méthode que l’on rencontre consiste à enregistrer l’ensemble des Key dans une variable et l’ensemble des Items, dans une autre.
ii = Dico.keys
jj = Dico.items

L’extraction se fait ensuite selon le même principe, même si la syntaxe est différente; on va redemander le N° d’index de la valeur à extraire; à noter qu’ici l’Option Base 1 ne fonctionne pas et que la première valeur est la valeur N° 0.

Range("I1") = ii(3)
Range("J1") = jj(3)

Il ne nous reste plus qu’à libérer la mémoire de nos variables :
Set Dico = Nothing: Erase ii: Erase jj

Ci-dessous le fichier au format .xls contenant les exemples de cet article.
Dictionnaire