14. Instructions groupées et structures de contrôle

14.1. Expressions groupées

R est un langage qui évalue les expressions qui lui sont fournies et retourne un résultat:

> c(1, 2, 3)
[1] 1 2 3

On peut affecter le résultat de l’évaluation d’une expression à une variable pour réutilisation ultérieure:

> v <- c(1, 2, 3)

Les expressions peuvent être groupées entre accolades { }. Chacune des instructions élémentaires est exécutée. La valeur retournée est le résultat de la dernière expression du groupement:

> { x <- c(1, 2, 3) ; y <- c(4, 5, 6) ; c(7, 8, 9) }
[1] 7 8 9
> x
[1] 1 2 3
> y
[1] 4 5 6

Un autre exemple:

> sample_stats <- {
+ sample <- rnorm(1000, 5, 10)
+ stats <- c(mean(sample), median(sample), var(sample))
+ }

> head(sample)
[1]   3.848532  -1.208626  14.149470  14.088703 -13.269124  -6.111380

> stats
[1]   4.758661   4.716693 103.390498

> sample_stats
[1]   4.758661   4.716693 103.390498

Les expressions groupées sont utiles pour exécuter plusieurs tâches lorsque la syntaxe d’une fonction requiert une seule expression:

> with(titanic, { print(head(Joined)) ; print(tail(Age))} )

14.2. Structures de contrôle

14.2.1. Exécution conditionnelle

En R, l’exécution conditionnelle possède la structure suivante:

> if (expr_1) expr_2 else expr_3

expr_1 doit être une simple valeur logique. expr_2 et expr_3 peuvent être des instructions simples ou groupées.

Here is a basic example:

> x <- -2
> if (x >=0) sign_of_x <- "positive" else sign_of_x <- "negative"
> sign_of_x
[1] "negative"

> x <- 2
> if (x >=0) sign_of_x <- "positive" else sign_of_x <- "negative"
> sign_of_x
[1] "positive"

On peut utiliser le fait que l’évaluation d’une expression groupée est le résultat de l’évaluation de la dernière expression:

> x <- -2
> sign_of_x <- if (x >=0) {"positive"} else {"negative"}
> sign_of_x
[1] "negative"
> x <- 2
> sign_of_x <- if (x >=0) {"positive"} else {"negative"}
> sign_of_x
[1] "positive"

L’exécution conditionnelle possède également un else if:

if ( test_expression1) {
   statement1
} else if ( test_expression2) {
   statement2
} else if ( test_expression3) {
   statement3
} else
   statement4

Les opérateurs logiques && et || sont utilisés pour construire des prédicats complexes:

> sign_of_x <- if (x >0 || x==0) {"positive"} else {"negative"}

Important

Les opérateurs & and | appliquent les conditions logiques sur des vecteurs de dimension supérieure à 1, élément par élément. alors que && et || sont utilisés avec des scalaires (vecteurs de longueur 1). Le second opérande n’est évalué que si nécessaire.

La fonction ifelse() est une version vectorisée de la construction if/else. Elle est de la forme ifelse(condition, a, b) et retourne un vecteur logique de taille, la longueur du plus long vecteur passé en argument. Il est évalué à a[i] si condition[i] est TRUE, à b[i] sinon:

> ifelse(c(-1,0,1) >=0, "positive", "negative")
[1] "negative" "positive" "positive"

14.2.2. Répétition d’instructions: for, repeat et while

On peut implémenter la répétition d’instructions avec une syntaxe de la forme:

> for (name in expr_1) expr_2

name est la variable de boucle, expr_1 retourne un vecteur, et expr_2 est souvent une expression groupée de plusieurs instructions. expr_2 est évaluée autant de fois que nécessaire pour chaque valeur de name prise séquentiellement dans le vecteur expr_1.

Here is a very basic example:

> for(i in 1:5){
+ sq <- i*i
+ print(c(i,sq))
+ }

[1] 1 1
[1] 2 4
[1] 3 9
[1]  4 16
[1]  5 25

Avertissement

R étant un langage vectorisé, les boucles for sont utilisés de façon beaucoup moins fréquentes que dans d’autres langages. La vectorisation permet une écriture plus compacte et plus lisible (et donc une plus grande maintenabilité) et également une exécution plus rapide. L’utilisation de boucles for inutiles est un signe de mauvaise appropriation du langage.

On peut également répéter des instructions avec while selon la syntaxe while (condition) expr. Par rapport à la boucle for, il faut :

  • préciser l’affectation intiale de la variable de boucle

  • gérer l’évolution de la variable de boucle

On utilisera ce type de construction lorsque l’ensemble des valeurs à parcourir n’est pas connu à l’entrée de la boucle.

L’exemple précédent réécrit avec une boucle while:

> i <- 1
> while ( i<=5) {
+ sq <- i*i
+ print(c(i,sq))
+ i <- i+1
+ }

[1] 1 1
[1] 2 4
[1] 3 9
[1]  4 16
[1]  5 25

R dispose également de repeat, utilisé avec la syntaxe repeat expr:

> i <- 1
> repeat {
+ sq <- i*i
+ print(c(i,sq))
+ i <- i+1
+ if (i>5) break
+ }

[1] 1 1
[1] 2 4
[1] 3 9
[1]  4 16
[1]  5 25

On utilise break pour terminer la boucle.

Astuce

while et repeat fonctionnent de façon très similaire. La différence entre les deux est que while évalue la condition de continuation au début de la boucle alors que repeat l’évalue à la fin. Une autre différence est que repeat nécessite l’emploi explicite de break pour terminer la boucle.