Tri « sur place » de listes avec python

Je n’en avais jamais eu l’utilité jusqu’à présent, et ce n’est donc que récemment que j’ai découvert le tri de listes de python. Ça marche vite et bien, avec du code compact!

Le prototype de la méthode est list.sort([cmp[, key[, reverse]]]) :

  • sans argument, la méthode tente d’utiliser les opérateurs de comparaison implémentés dans les objets de la liste.
  • cmp : une fonction prenant deux arguments et qui retourne 0, -1, ou 1 selon que le premier argument est considéré inférieur, égal ou supérieur au deuxième argument
  • key: une fonction qui prend un objet en argument et qui renvoie un champ clé sur lequel on souhaite classer. Sort utilise cette clé pour le tri en utilisant les comparaisons intrinsèques de la clé.
  • reverse: un booléen qui permet un classement inversé. Il est False par défaut.

Pour des objets élaborés (par exemple, des performances de saut en longueur, qui contiennent la date, la longueur et le sportif), on peut avoir implémenté les opérateurs __cmp__, __eq__ ou __ne__ , pour que le sort les utilise automatiquement (comparaison par date puis par longueur sur notre exemple).

Mais il arrive que ces opérateurs de comparaison n’aient pas vraiment de sens, dans mon cas, des objets représentant des enregistrements, que je souhaite classer par id. Ici, comparer intrinsèquement deux objets ne veut pas dire grand chose.

Je pourrais alors procéder comme suit :

# ma fonction qui donne la clé
def get_key_for_object(obj):
    return obj.id

# je récupère mes objets
maListe = get_records()
# je classe
maListe.sort(key=get_key_for_object)

On remarque que la fonction get_key_for_object est vraiment très simple : on remplace la définition de la fonction par une simple fonction lambda dans l’appel du sort.

maListe.sort(key=lamba obj: obj.id)

Je peux même trier des objets hétéroclites du moment qu’ils aient bien tous la propriété id!

Sur le même principe, je peux définir une fonction cmp. Imaginons que je veuille classer des nombres complexes en fonction de leur module, je pourrais faire ceci :

def compare_magnitudes(a,b):
    a_m = sqrt(a.real*a.real + a.im*a.im)
    b_m = sqrt(b.real*b.real + b.im*b.im)
    # il ne reste plus qu'à comparer deux float
    return cmp(a_m, b_m)

mesComplexes.sort(cmp=compare_magnitudes)

Encore plus simplement, si mes complexes definissaient un propriété magnitude:

mesComplexes.sort(cmp=lambda a,b: cmp(a.magnitude, b.magnitude))

Tout ça est donc bien pratique lorsque nos objets ne définissent pas d’opérateurs de comparaison, ou bien que l’on souhaite ponctuellement définir un type de tri spécifique.

Vous aimerez aussi...

Laisser un commentaire