[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

[VBA] Trier un tableau avec un double-clic

Voici un petit script qui permet de trier un tableau en fonction de la colonne du tableau dans laquelle l’utilisateur fait un double-clic; nous allons aborder ici 2 fonctions d’Excel : la programmation des macros dites évènementielles et la fonction de tri.

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)

Dim myRange As Range

Cancel = True

Set myRange = Range("D10").CurrentRegion

If Not Intersect(myRange, Target) Is Nothing Then
    myRange.Sort key1:=Cells(myRange.Cells(1).Row, Target.Column), Header:=xlYes
End If

Target.Select

End Sub

Explications

La première notion que nous allons aborder est celle d’évènement.
Un évènement peut être l’ouverture d’un classeur, un clic droit, un changement d’onglet etc… ici, l’évènement qui va automatiquement déclencher notre macro est le double-clic.

Pour configurer l’évènement, nous ouvrons la fenêtre VBA (ALT + F11) et accédons à la fenêtre de projets (CTRL + R) si celle-ci n’est pas ouverte.
Evenement

Nous pouvons choisir d’activer l’évènement à tout le classeur ou bien à une seule des feuilles de ce classeur.
Dans notre cas de figure, il s’agit de l’appliquer à une seule feuille, nous allons donc là sélectionner dans notre fenêtre de projets à gauche et allons ensuite sélectionner l’option Worksheet du petit menu déroulant comme indiqué sur l’image.
Si nous avions voulu appliquer l’évènement à tout le classeur, nous aurions sélectionné l’option ThisWorkbook dans la fenêtre de gauche et ensuite l’option Workbook du menu déroulant.
En sélectionnant l’option Worksheet, le message suivant apparait dans notre fenêtre de droite

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

End Sub

et l’option SelectionChange dans le menu déroulant de droite.
Nous pouvons effacer Private Sub Worksheet_SelectionChange(ByVal Target As Range)
End Sub
et nous allons sélectionner l’option BeforeDoubleClick dans le menu déroulant de droite.
Apparait alors le code suivant dans la fenêtre générale :

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)

End Sub

Après avoir déclaré notre variable Dim myRange As Range, nous instruisons Excel sur la gestion du double-clic Cancel = True : en temps normal, lorsque nous double-cliquons dans une cellule, le curseur sélectionne cette cellule et se met en position d’écriture. Cette commande empêche le curseur de sélectionner la cellule car ce n’est pas, ici, le but recherché par le double-clic.

L’étape suivante consiste à définir la plage pour laquelle le double-clic sera actif :
Set myRange = Range("D10").CurrentRegion
Une plage est un « objet », donc la variable myRange à laquelle nous allons allouer cette plage est suivi de la commande Set (voir l’article : Déterminer la dernière ligne/colonne d’un tableau pour de plus amples explications).
La commande .CurrentRegion qui suit la cellule D10 (que nous avons choisie arbitrairement, toute autre cellule appartenant au tableau ou adjacente à celui-ci fonctionne)  demande à Excel de prendre en compte la plage de cellules adjacentes et non vides autour de la cellule D10. Pour mieux comprendre son fonctionnement, voici une image sur laquelle apparait en jaune la plage sélectionnée par la commande Range("B4").CurrentRegion.
CurrentRegion

Dans notre cas, la plage correspond au tableau que l’on va trier.

La commande If Not Intersect(myRange, Target) Is Nothing Then va vérifier si le double-clic doit générer le tri du tableau ou pas; pour cela elle va contrôler que le double-clic a lieu dans notre plage myRange précédemment définie, autrement dit, dans le tableau.
Nous connaissons donc la plage définie par myRange; Target correspond à la cellule sur laquelle nous double-cliquons.
Traduisons notre commande : si (If) l’intersection (Intersect) entre la plage de mon tableau et la cellule sur laquelle nous double-cliquons (myRange, Target ) n’est pas rien (Not … Is Nothing) Then (alors exécuter…). autrement dit si la cellule sur laquelle nous double-cliquons se trouve dans la plage de notre tableau, alors exécuter…

myRange.Sort effectue le tri pour la plage myRange.

Header:=xlYes demande à la macro de considérer la première ligne de la plage comme étant l’en-tête du tableau et de ne pas l’inclure dans le tri; une valeur xlNo aurait également procédé au tri de la première ligne de la plage séléctionnée.

key1:=Cells(myRange.Cells(1).Row, Target.Column) cette dernière partie du code détermine la clé du tri; dans un cas figure normal, on peut trier un tableau avec plusieurs clés de tri (Key1, Key2, Key3… en fonction de l’ordre du tri).
Mais, dans notre cas de figure, puisqu’on ne peut double-cliquer que sur une seule cellule à la fois, nous sommes limités à une seule valeur de tri. La clé de tri correspond à la cellule de l’en-tête choisie pour réaliser le tri : Key1 sera donc suivi de l’adresse d’une cellule appartenant à l’en-tête du tableau.

La syntaxe de la commande Cells est la suivante : Cells(N° de ligne de la cellule, N° de colonne de la cellule).
myRange.Cells(1).Row représente donc le N° d’une ligne et Target.Column, le N° d’une colonne.
Target.Column identifie le N° de colonne de la cellule sur laquelle nous avons double-cliqué; .Column signifie N° de colonne, à ne pas confondre avec Columns qui représente une colonne physique.

Pour myRange.Cells(1).Row, c’est à peine plus compliqué. Myrange identifie notre plage; une plage est composée de cellules.
Puisque nous avons une collection (une série) identifiée de cellules, nous savons que chaque cellule de cette collection possède un index (autrement dit un N° d’ordre classant cette cellule par rapport aux autres cellules de la plage; voir l’article Classer les onglets d’un classeur par ordre alphanumérique pour plus d’informations concernant le fonctionnement de l’index). Nous savons que la première cellule de notre plage myRange.Cells(1) correspond à la première cellule composant l’en-tête de notre tableau, autrement dit la cellule B2 nommée N° INSEE.
Pour vous en convaincre, tapez myRange.Cells(1).Select dans le code programme juste sous l’instruction Set myRange = Range("D10").CurrentRegion

Il ne nous en faut pas plus pour définir le N° de ligne de notre cellule. Comme nous avons extrait le N° de colonne, nous allons récupérer le N° de ligne en ajoutant la commande .Row (qui est le N° de ligne à ne pas confondre avec Rows qui représente une ligne physique dans la grille).
Les paramètres de la cellule servant de clé pour le tri sont maintenant définis; il nous reste à spécifier la commande Target.Select afin de maintenir le curseur sur la cellule sur laquelle a été effectué le double-clic.

Fichier au format .xls ci-dessous
Tri Auto