Parcourir par le rang
La boucle for comptée trouve enfin son emploi — et le piège du cran de trop se voit à l'exécution.
Quand le rang lui-même vous intéresse, for … in ne suffit plus : il donne les valeurs, jamais
leur position. C’est le moment de reprendre la boucle comptée de la section 4.2.
@entry(demarrer)
object MonProgramme {
demarrer() {
var mesures := [12, 19, 7];
for (var i := 0; i < mesures.length; i := i + 1) {
Console.print(text: $"mesure {i + 1} sur {mesures.length} : {mesures[i]}");
}
}
}
Les trois clauses, appliquées à un tableau
for (var i := 0; i < mesures.length; i := i + 1) {
Chaque clause dit maintenant quelque chose de précis :
var i := 0— on part du premier rang, qui est zéro ;i < mesures.length— on continue tant qu’on n’a pas dépassé le dernier ;i := i + 1— on avance d’un rang.
La 4.2 présentait ces trois clauses sur une suite de nombres qui ne servait à rien d’autre qu’à
compter. Voici ce à quoi elles servent vraiment : i n’est plus un nombre, c’est un rang,
et mesures[i] est l’élément qui s’y trouve.
Remarquez que l’affichage se sert des deux : {i + 1} pour parler au lecteur, qui compte à
partir de 1, et mesures[i] pour atteindre l’élément, qui se compte à partir de 0. Le décalage
est là, tout entier, sur une seule ligne.
< et non <=
C’est la faute la plus courante de tout ce cours, et elle vaut qu’on s’y arrête.
Trois éléments, rangs 0, 1 et 2. La condition i < 3 laisse passer 0, 1 et 2, puis s’arrête :
exactement les trois rangs qui existent. Écrivez i <= mesures.length et la boucle fait un tour
de plus, avec i valant 3 — un rang qui n’existe pas.
Le résultat n’est pas un tableau mal parcouru, c’est un programme qui s’arrête :
12
19
7
uncaught error — IndexOutOfRangeError : index 3 out of range for an array of length 3
Les trois lignes s’affichent, puis tout tombe. Voilà pourquoi la 4.3 disait que la faute la plus
classique du for compté est de s’arrêter un cran trop tôt ou trop tard : voici le cran de trop,
et ce qu’il coûte.
À l’envers, sans compter
Remonter un tableau est un besoin si courant qu’il ne demande pas de boucle comptée :
for mesure in reverse mesures {
Console.print(text: $"{mesure}");
}
Le mot reverse se glisse entre in et ce qu’on parcourt, et la boucle part du dernier élément.
Tout ce que la sous-section précédente vous a fait éviter — l’indice de départ, la condition, le
sens de l’avancement — disparaît avec lui. Un tableau vide ne fait aucun tour, dans un sens comme
dans l’autre.
reverse n’est pas un mot réservé pour autant. Il ne prend ce sens qu’ici, juste après le
in d’un for ; ailleurs il reste un nom comme un autre, et rien ne vous empêche d’appeler une
variable reverse.
Lequel choisir
La règle de la 4.3 tient toujours, et cette sous-section ne fait qu’en montrer l’exception :
for … indès que vous parcourez des valeurs, etfor … in reversedès que vous les parcourez à l’envers. Pas de rang à écrire, donc pas de rang à rater — la boucle ne peut pas sortir des bornes.forcompté quand le rang lui-même vous sert : pour l’afficher, pour comparer un élément à son voisin, pour n’en parcourir qu’une partie.
En cas de doute, for … in. Le rang qu’on n’écrit pas est un rang qu’on ne peut pas fausser — et
depuis que reverse existe, remonter n’est plus une raison d’en écrire un.
À vous
- Remplacez
<par<=et exécutez. Trois lignes, puis l’erreur. - Parcourez à l’envers à la main —
var i := mesures.length - 1, conditioni >= 0, avancementi := i - 1— puis récrivez la même chose avecfor mesure in reverse mesures. Trois clauses contre un mot, pour le même résultat. - N’affichez qu’un élément sur deux, en avançant de
2au lieu de1. - Réécrivez la boucle en
for mesure in mesureset voyez ce que vous perdez : plus moyen d’écrire « mesure 2 sur 3 ».