Trier les types intégrés
slices.Sort trie toute slice dont le type d'élément est ordonné : entiers, flottants et chaînes. Elle trie sur place et ne renvoie rien.
Sortie :
[3 7 19 42 88]
[Bob Carl alice lisa]
true
2 true
Les chaînes se trient par octets, donc chaque lettre ASCII majuscule vient avant chaque lettre minuscule. C'est rarement ce qu'un utilisateur attend pour des noms. La section suivante corrige cela.
Le package slices est arrivé avec Go 1.21. Son Sort est un pattern-defeating quicksort : O(n log n), sur place, et non stable.
Un ordre personnalisé avec SortFunc
slices.SortFunc prend une fonction de comparaison func(a, b T) int. Renvoyez un nombre négatif quand a doit venir en premier, un nombre positif quand c'est b, et zéro quand ils sont égaux. La fonction cmp.Compare renvoie exactement cela pour les types ordonnés.
strings.ToLower dans une comparaison alloue une nouvelle chaîne chaque fois que son entrée contient une majuscule, et la comparaison s'exécute environ n log n fois. Pour de grosses slices, calculez les clés en minuscules une seule fois. Pour des noms dans d'autres langues (accents, règles locales), utilisez golang.org/x/text/collate, qui est hors de la bibliothèque standard.
Une fonction de comparaison doit être cohérente : si elle dit que a vient avant b, elle doit dire que b vient après a. Une fonction qui enfreint cette règle (par exemple en renvoyant -1 dès que deux valeurs diffèrent) produit une slice mal ordonnée sans aucune erreur. Soustraire des entiers (return a - b) paraît élégant mais déborde pour les grandes valeurs ; utilisez cmp.Compare.
Trier des structs
La fonction de comparaison reçoit des éléments, donc trier des structs selon un champ est le même appel :
Les employés avec des salaires égaux peuvent sortir dans n'importe quel ordre ici, parce que SortFunc n'est pas stable. Si vous avez besoin d'un ordre garanti, départagez avec d'autres champs ou utilisez un tri stable.
Trier sur plusieurs champs
Comparez d'abord le champ le plus important et ne passez au suivant qu'en cas d'égalité. cmp.Or (Go 1.22) renvoie son premier argument non nul, ce qui ramène le tout à une ligne :
Sortie :
eng 150 Cy
eng 120 Ana
eng 120 Eve
sales 90 Bob
sales 90 Dee
Chaque comparaison est évaluée même quand la première tranche, puisque ce sont de simples arguments. Cela coûte peu pour des comparaisons de champs. Quand un critère de départage est coûteux, écrivez à la main la chaîne if c := ...; c != 0 { return c }.
Tri stable
Un tri stable garde dans leur ordre d'origine les éléments qui se comparent égaux. Cela compte quand l'entrée a déjà un ordre significatif, par exemple des enregistrements triés par date que vous regroupez maintenant par utilisateur.
Ce code affiche [{ana 2} {ana 4} {bob 1} {bob 3} {bob 5}] : pour chaque utilisateur, la séquence d'origine est conservée. Le tri stable demande plus de travail, donc ne l'utilisez que lorsque l'ordre des éléments égaux compte.
Trier une map
Les maps n'ont pas d'ordre. Pour afficher une map triée par clé, triez ses clés : slices.Sorted(maps.Keys(m)) (Go 1.23). Pour trier par valeur, triez les clés avec une comparaison qui consulte les valeurs :
Le départage sur le mot compte : sans lui, chan et slice (tous deux à 7) s'afficheraient dans un ordre différent d'une exécution à l'autre, parce que les clés sortent de la map dans un ordre aléatoire. Voir les maps pour en savoir plus.
Le package sort : sort.Slice et compagnie
Avant Go 1.21, le tri passait par le package sort. Vous le verrez dans beaucoup de code existant :
sort.Ints(nums)
sort.Strings(names)
sort.Slice(staff, func(i, j int) bool {
return staff[i].Salary < staff[j].Salary
})
sort.SliceStable(staff, func(i, j int) bool { ... })
Les différences à connaître :
sort.Slice | slices.SortFunc | |
|---|---|---|
| La fonction reçoit | des indices i, j | des éléments a, b |
| Renvoie | un bool (i est-il inférieur à j) | un int (négatif, zéro, positif) |
| Sécurité du typage | prend un any, utilise la réflexion | générique, vérifié à la compilation |
| Vitesse | plus lent | plus rapide |
Un bug courant avec sort.Slice consiste à capturer une autre slice que celle qu'on trie, puisque la fonction less indexe par position. SortFunc ne peut pas avoir ce bug car elle vous donne les éléments.
Le type sort.Interface (Len, Less, Swap) est la forme la plus ancienne. C'est encore la façon de trier des données qui ne forment pas une seule slice, comme deux slices parallèles qui doivent bouger ensemble. Depuis Go 1.22, sort.Ints, sort.Strings et sort.Float64s appellent simplement slices.Sort.
Erreurs courantes
- S'attendre à ce que
Sortrenvoie la slice triée. Elle trie sur place et ne renvoie rien. Utilisezslices.Sorted(slices.Values(s))si vous voulez une nouvelle slice triée, ouslices.Cloned'abord. - Supposer que les éléments égaux gardent leur ordre. Seules les variantes
Stablele promettent. - Soustraire pour comparer.
a - bdéborde. Utilisezcmp.Compare. - Trier des flottants contenant NaN.
cmp.Compareplace NaN avant toutes les autres valeurs, ce qui garde le tri cohérent. Une comparaisona < bécrite à la main, non.
Questions fréquentes
Comment trier une slice en Go ?
Pour des nombres et des chaînes, appelez slices.Sort(s) (Go 1.21). Elle trie sur place dans l'ordre croissant. Pour tout le reste, ou un autre ordre, utilisez slices.SortFunc(s, func(a, b T) int { ... }), où la fonction renvoie un nombre négatif si a vient en premier, positif si c'est b, et zéro s'ils sont égaux.
Comment trier une slice dans l'ordre décroissant en Go ?
Inversez les arguments dans la comparaison : slices.SortFunc(s, func(a, b int) int { return cmp.Compare(b, a) }). Ou triez dans l'ordre croissant puis appelez slices.Reverse(s).
Comment trier une slice de structs sur plusieurs champs en Go ?
Comparez le premier champ, et ne passez au suivant qu'en cas d'égalité. cmp.Or (Go 1.22) fait exactement cela : return cmp.Or(cmp.Compare(a.Dept, b.Dept), cmp.Compare(b.Salary, a.Salary), strings.Compare(a.Name, b.Name)) renvoie le premier résultat non nul.
Quelle est la différence entre sort.Slice et slices.SortFunc ?
sort.Slice(s, func(i, j int) bool) est l'ancienne API : elle prend une fonction less sur des indices et utilise la réflexion pour échanger les éléments. slices.SortFunc(s, func(a, b T) int) est générique, vérifiée par le compilateur, reçoit directement les éléments, et elle est plus rapide. Le nouveau code devrait utiliser le package slices ; sort.Slice reste courant dans le code écrit avant Go 1.21.