2.8 Les structures de contrôle
Nous allons dans cette partie attaquer un des éléments au coeur de tout langage de programmation : les structures de contrôle. Pour l'instant, nous savons uniquement créer des variables, les modifier, les selectionner, et réaliser des opérations diverses avec ces variables. Il est temps de rendre nos programmes un peu plus dynamique, à l'aide des structres de contrôle. Les structures de contrôles permettent de contrôler le "flux" des instructions : certaines permettent de n'exéctuer des lignes de code que si une condition est remplie, quand d'autres permettent de répéter automatique plusieurs fois une même suite d'instructions.
La famille des if
Les premières structures de contrôle que nous allons voir sont celles qui tournent autour de la condition "if". Elle permettent d'éxcuter du code seulement si une certaine condition est validée. Si la condition n'est pas remplie, le code n'est pas exécuté.
Le if
La première structure de cette famille est le if
. Cette structure nous permet d'exécuter une suite d'instruction uniquement si une condition est remplie. La structure se présente ainsi :
if(condition) {
#du code qui n'est exécuté que si condition est TRUE
}
Examinons cela en détail. On écrit d'abord le mot clef if
, suivit d'une condition entre les ()
. Puis on écrit entre {}
le code qui doit être exécuté si la condition est vraie. On appelle cette partie entre accolades le corps du if
. La condition entre les ()
doit être une expression, qui lorsqu'elle est évaluée, renvoit en booléen (TRUE
ou FALSE
).
Voyons avec un véritable exemple ce que cela donne :
age = 25
if(age >= 18) { #TRUE, on entre donc dans le corps de la condition
print("Vous êtes majeur, félicitation !") #on exécute ce code
}
La condition entre les ()
est une expression qui doit produire TRUE
ou false
. Ici age >= 18
est bien évaluée à TRUE
carage = 25
. Comme la condition est vraie, on rentre alors dans le corps de la boucle entre {}
pour exécuter le code qui s'y trouve. On affiche alors la chaine demandée avec l'instruction print("Vous êtes majeur, félicitation !")
. Puis on sort du corps du if
et R continue de lire la suite des instructions du programme normalement.
Si vous changez la valeur de age
pour 12
, vous verrez qu'il ne se passera rien. La condition age >= 18
étant évaluée à FALSE
, le programme ne va donc pas rentrer dans les {}
et n'éxécutera pas le code qui s'y trouve :
age = 12
if(age >= 18) { #FALSE, le programme continue directement aprés le corps du if
print("Vous êtes majeur, félicitation !") #Ce code n'est pas exécuté
}
C'est pour cela que l'on parle de structures de contrôles : une instruction if permet de contrôler la façon dont les instructions sont exécutés. Certaines instructions peuvent ainsi n'être exécutés que si une condition est vraie, et ne pas l'être autrement.
L'indentation :
Remarquez que le code entre les {}
est toujours décalé verticalement vers la droite : l'instruction avec le print n'est pas alignée verticalement avec le if. Ce décalage permet de mieux repérer visuellement le code qui fait parti du corps du if
, et de le différencier du reste du programme. Ce décallage des lignes s'appelle l'indentation.
Le if else
L'instruction if
est trés utile, mais souvent l'on souhaite exécuter une action si une condition est vraie, et en exécuter une autre dans le cas contraire. Pour cela, il existe la structure if else
, que l'on peut traduire en français par "Si... Sinon". Cela consiste à exécuter le corps du if
si la condition est vraie, et sinon on exécute les instructions contenues dans le else
. Voici un exemple de code utilisant cette structure :
age = 25
if(age >= 18) {
print("Vous êtes majeur !")
} else {
print("Vous êtes mineur !")
}
Si on exécute ce code, il affichera "vous êtes majeur !"
, car la condition est vraie. Si on change la valeur de age
pour la mettre à 12
, alors les instructions dans le if
ne seront pas exécutées, et à l'inverse celles contenues dans le corps du else
seront lue par notre ordinateur. Ici, c'est le message "Vous êtes mineur !"
qui s'affichera dans la console.
Cette variante du if
est trés souvent utilisée en pratique, par exemple pour tester une condition et faire soit une action si elle est vraie, soit une autre action dans le cas contraire.
Le if else if
Il existe enfin une troisème instruction de la famille des if
, qui est le if... else if
. Cela nous permet d'enchainer plusieurs conditions les unes à la suite des autres;, alors que un if
ou if else
ne permettent que de tester une seule condition. Regardons cette structure avec un exemple :
age = 25
if(age < 12) {
print("vous êtes trés jeune !")
} else if (age < 18) {
print("Vous etes un ado !")
} else if (age < 45) {
print("Vous êtes un adulte !")
}
Cette structure nous permet de chainer les if
: la seconde condition age < 18
n'est regardée que si la premiére condition est fausse. Si cette seconde condition est évaluée à FALSE
également, alors on regarde le troisiéme condition, et ainsi de suite. On peut enchainer autant de else if
que l'on veut.
Il est courant d'enchainer les else if, puis de finir avec un else
qui donne les instructions à suivre si aucun des cas précédent n'a été rencontré :
age = 80
if(age < 12) {
print("vous êtes trés jeune !")
} else if (age < 18) {
print("Vous etes un ado !")
} else if (age < 45) {
print("Vous êtes un adulte !")
} else {
print("Vous approchez de la sagesse !")
}
Ici, comme aucune des conditions rencontrée n'est valide, c'est le code rencontré dans le else
qui sera exécuté.
Cette structure en if else if
est également trés courante, quand la condition que l'on veut tester pour prendre plusieurs cas possibles, et non seulement deux comme avec un simple if else
. Ainsi, selon ce que vous voulez faire, il y aura probablement une des trois instructions de la famille des if
qui sera adaptée à votre besoin.
Les structures d'itérations
Nous allons voir maintenant de nouvelles structures de contrôle, les structures d'itérations. Elles permettent de répéter plusieurs fois des instructions, jusqu'à ce qu'une condition soit remplie. Elles sont trés pratiques pour éviter au développeur d'éviter d'écrire plusieurs fois la même chose, le programme s'en chargeant à sa place ! Un bon développeur n'est-il pas un développeur qui se simplifie la vie ?
Il existe en R trois structures de boucles :
- la boucle
for
qui parcours les éléments d'un vecteur. - la boucle
while
qui se répéte tant qu'une condition n'est pas remplie. - la boucle
repeat
qui se répéte tant qu'elle ne rencontre pas d'instruction de sortie.
La boucle for
La boucle for
est une instruction que la plupart des langages de programmations possédent, tellement elle est utile et universelle. Elle permet de répéter les instructions présentent dans le corps de la boucle une fois pour chaque élément dans un vecteur. Regardons cette structure :
for(i in mon_vecteur) {
#instructions à réaliser
}
Aprés le mot clef for
on écrit entre ()
deux éléments, séparés par le mot clef in
. mon_vecteur
correspond au vecteur pour lequel on exécutera les instructions du corps de la boucle une fois par élément, et i
est le nom que l'on voudra que R donne à la variable qui contiendra chaque élement du vecteur. Vous pouvez choisir n'importe quel nom qui vous convient.
Regardons ce que cela donne avec un exemple, afin que les choses soient plus claires :
for(element in c(1,2,3,4,5)) {
print(element)
}
Si vous exécutez ce code, vous allez voir qu'il affiche dans la console les éléments du vecteur : 1, 2, 3, 4 et 5. La boucle for se sépare en deux parties : entre les ()
on précise le vecteur que la boucle va parcourir, ici le vecteur c(1,2,3,4,5)
. element
correspond au nom que R donnera à une variable accessible dans la boucle, qui aura pour valeur l'élement du vecteur en cours. Enfin entre {}
on retrouve le corps de la boucle, qui sera éxécuté autant de voir qu'il y a d'éléments dans notre vecteur.
On peut donc comprendre la boucle comme ayant le sens suivant : "éxécuter les instructions du corps de la boucle une fois pour chaque élément du vecteur c(1,2,3,4,5)
, et on affectera la valeur de chaque élément à une nouvelle variable element
à chaque tour de la boucle, afin que l'on puisse savoir comment l'utiliser depuis le corps de la boucle".
Lecture pas à pas :
Voici comment notre ordinateur lit notre boucle, étape par étape. Il lit la partie entre ()
et comprends que l'on à décider de nommer element
les éléments du vecteur qui sera parcouru. Puis aprés le in
, il vois que l'on souhaite parcourir le vecteur c(1,2,3,4,5)
. R regarde la première valeur de notre vecteur, qui est 1
. Il crée une variable element
et lui affecte le nombre 1
. Puis il entre dans le corps de la boucle, et lit l'instruction print(element)
. Comme vous venons de créer cette variable, elle peut être affichée dans la console, qui affiche 1
. Ceci étant la seule intruction du corps de la boucle, le programme peut alors passer au second élement de notre vecteur.
Il affecte la valeur du second élément du vecteur à la variable element
, puis recommence à éxécuter les instructions du corps de la boucle. Il affiche la valeur de element
, qui est de 2
maintenant. Les instructions étant finies, R passe alors au troisième élément du vecteur. Et ainsi de suite, jusqu'à ce que la boucle est parcourue tous le vecteur. Une fois le vecteur entiérement parcouru, R peut alors lire les instructions situées aprés la boucle.
Remarque que la variable element
qui est crée par la boucle est visible dans l'environnement : vous pourez donc y faire appel par la suite si vous le voulez.
Faites donc bien attention en choissant le nom de cette variable, en n'en utilisant pas un que vous aviez déjà utilisé dans votre programme !
Une boucle for un peu plus longue
la boucle for est bien pratique, mais comment faire si nous voulons par exemple ajouter ensemble les nombres de 1 à 100 ? Nous devons créer à la main un vecteur c(1,2,...,100)
contenant tous les nombres entre 1 et 100 ? Et si nous souhaitons compter jusqu'a 1000 ? 10 000 ? Heureusement pour nous, il existe en R une syntaxe spéciale pour créer un vecteur contenant uniquement des integer
qui se suivent :
suite1 = 1:10 #Créer un vecteur avec les nombres entre 1 et 10
suite2 = 10:100 #Créer un vecteur des nombres entre 10 et 100
n = 1
m = 100
suite3 = n:m #la suite des entiers entre 1 et 100
Nous découvrirons dans deux chapitres d'autres façons de produire des suites de nombres. En attendant, cette technique est trés pratique pour créer des vecteurs facilement, et peut nous servir à écrire des boucles. Calculons la somme des n
premiers entiers :
total = 0
n = 100
for(i in 1:n) {
total = total + i
}
print(total) #5050
Cette boucle toute simple parcours le vecteur des entiers de 1 à 100, et ajoute chaque nombre à une variable total. Une fois tous les nombres ajoutés entre eux, on affiche le résultat. Voyez comme on utilise la syntaxe 1:n
pour créer un vecteur c(1, 2, ..., n)
des n
premiers entiers, avec ici n = 100
.
Parcourir un vecteur autre que des nombres
La boucle for
peut prendre n'importe quel type de vecteur en entrée. Par exemple affichons la liste des premiéres présidents des Etats-unis :
presidents = c("Washington", "Adams", "Jefferson")
for (president in presidents) {
print(president)
}
#[1] "Washington"
#[1] "Adams"
#[1] "Jefferson
Attention à ne pas confondre dans l'instruction le nom de la variable president
qui sera utilisé pour retenir chaque valeur, et le nom du vecteur que l'on va parcourir; ici presidents
. Et n'oubliez pas le in
entre les deux.
Tout type de vecteur peut être parcouru de cette façon, qu'il soit logical
, numerique, ou character
.
La boucle while
La seconde structure d'ittération la plus utilisée est la boucle while
. Contrairement à un boucle for
qui répéte des instructions autant de fois que par éléments dans un vecteur, la boucle white
répéte les instructions tant qu'une condition n'est pas remplis. Voici sa structure :
while(condition) {
#code à éxéctuer
}
Cette instruction est trés pratique que vous ne savez pas à l'avance combien de fois pour allez devoir répéter vos instructions. Essayons de l'utiliser ajouter les entiers naturels les uns à la suite des autres, jusqu'a obtenir un total supérieur à 200.
total = 0
entier = 1
while(total < 200) {
total = total + entier #on ajoute l'entier courant au total
entier = entier + 1 #on passe à l'entier suivant
}
print(entier) #affiche 21
print(total) #affiche 210
Voyez l'astuce qui consiste à déclarer avant la boule while
une variable total
qui sera utilisé dans notre condition, et une variable entier
qui commence à 1 et qui augmentera de 1 à chaque tour de la boucle. Une fois que la condition de la boucle est remplie, alors le corps de la boucle n'est plus exécuté et R passe aux instructions suivant le corps de la boucle.
Sortir d'une boucle avec l'instruction break
Vous pouvez à tout moment sortir d'une boucle avec l'instruction break
. Si R rencontre cette instruction dans une boucle, il arrête alors imédiatement de parcourir le corps de la boucle, et considére qu'il a fini la boucle. Il va alors sauter à la fin de la boucle, ignorant les potentiels tours de boucle restants.
Regardons comment on peut utiliser cette instruction pour faire la somme des nombres entre 1 et 100, en s'arrêtant quand leur somme dépasse 200. On sait ce cas de figure va se présenter, car la somme totale des nombres entre 1 et 100 est de 5050. Il y a donc forcement un moment où ce total dépasse 200. Mais on ne sait pas exactement quand. Pour le trouver, nous allons simplement vérifier à chaque tour de la boucle si notre somme dépasse 200 ou non. Si c'est le cas, alors on sort de la boucle avec un break
. Si le total est inférieur à 200, on laisse la boucle continuer :
total = 0
for(i in 1:100) {
total = total + i
if(total > 200) {
break
}
}
print(total) #affiche 210
On utilise pour cela une instruction if
au sein de la boucle. A chaque ittération de la boucle on teste si total
est supérieur à 200. Si c'est le cas, on exécute le corps du if
, qui nous fait sortir de la boucle car il contient l'instruction break
. Si total
est inférieur à 200, alors la condition du if
est évaluée en FALSE
et son corps n'est pas exécuté. La boucle continue, jusqu'à avoir parcouru tous le vecteur, ou jusqu'à qu'elle finisse par rencontrer l'instruction break
.
Remarque : L'instruction breack
fonctionne avec n'importe quel type de boucle : for
, while
et repeat
. Dans tous les cas, elle permet de sortir de la boucle en cours.
Sauter une itération avec l'instruction next
Il arrive parfois que l'on ne souhaite pas sortir complétement de la boucle, mais simplement passer au tour suivant. Par exemple imaginons que l'on souhaite faire la somme des nombres entre 1 et 100, mais en ne comptant uniquement les nombres pairs. Notre boucle devra alors passer à l'itération suivante si le nombre est impair, et l'ajouter normalement au total si il est pair. On peut utiliser l'instruction next
pour dire à R que l'on souhaite passer a l'ittération suivante de notre boucle, comme ceci :
total = 0
for(i in 1:100) {
if(i%%2 != 0) {
next
}
total = total + i
}
print(total) #affiche 2550
L'instruction next
est très utile quand on ne souhaite pas appliquer les instructions à chaque tour de boucle, comme ici.
Remarque : Comme l'instruction break
, l'instruction next
fonctionne avec toutes les boucles existantes : for
, while
et repeat
.
La boucle repeat
Il existe une troisième façon d'écrire des boucles en R, avec l'instruction repeat
. Cette instruction répéte simplement les instructions du corps de la boucle tant qu'elle ne rencontre pas de break
! C'est pourquoi nous avons présenté les instructions break
et next
juste avant. Voici la structure d'une boucle repeat
:
repeat {
#écrire les instructions ici
}
Si vous voulez sortir d'une boucle repeat
vous devez utiliser une instruction break
. Cela se fait généralement via une condition, par exemple :
#Calculons la somme des nombres de 1 a 100 avec une boucle repeat
n = 0
total = 0
repeat {
n = n + 1
total = total + n
if(n == 100) {
break
}
}
print(total) #5050
N'oubliez pas cette instruction break
dans votre boucle repeat
, sinon cela va créer une boucle infinie ! Si vous creez une boucle infinie par erreur, vous pouvez toujours cliquer sur l'icone "stop" de la console qui apparaitera alors pour arrêter le programme.
Quand utiliser une boucle repeat ?
Cette boucle est moins souvent utilisée que les deux autres, mais elle est pratique dans certaines situations. regardons déjà quand utiliser les autres boucles.
Une boucle for
est utile quand on souhaite parcourir un vecteur, ou que l'on connait le nombre d'itérations à effectuer. Une boucle while
est plus intéressante quand le nombre d'ittération est inconnu mais que la condition pour sortir de la boucle l'est.
La boucle repeat
est proche de la boucle while
. Mais la boucle repeat
ne dépend d'aucune condition externe au contraire d'un while
. Si la condition de sortie de la boucle dépend uniquement de ce qui se passe dans la boucle et pas d'une variable créee à l'extérieur, alors while
peut être plus approprié.
A retenir :
- Vous pouvez exécuter du code conditionnellement à une condition avec les instructions de la famille des if, que sont
if
,else if
etif else if
. - La condition doit être n'importe quelle expression qui renvois
TRUE
ouFALSE
quand elle est évaluée. - Vous pouvez utiliser une boucle
for
pour parcourir un vecteur et répéter des instructions pour chaque élement de ce vecteur. - Si vous ne savez pas combien de fois à l'avance votre boucle va être appelée, vous pouvez utiliser une boucle
while
qui répéte les instructions tant que la condition entre parenthéses n'est pas remplie. - Vous pouvez sortir d'une boucle à tout moment avec l'instruction
break
, et passer à l'itération suivante avec l'instructionnext
. Les deux fonctions pour les trois types de boucles existants. - Le troisiéme type de boucle, la boucle
repeat
, répéte les instructions du corps de la boucle tant qu'elle ne rencontre pas d'instructionbreak
. - Vous pouvez utiliser la syntaxe
n:m
pour créer un vecteur d'entiers consécutifs entren
etm
. C'est très utile pour répétern
fois des instructions, il suffit de faire une bouclefor
sur le vecteur1:n
.