Dans ce chapitre nous apprendrons à créer des conditions. Ceci permettra d’adapter le déroulement de nos programmes à certains paramètres, tels que la valeur des variables.
- Opérateurs de comparaison
- La structure if-else
- La structure case-when
- Les conditions ternaires
- Exercices
Opérateurs de comparaison
Les conditions (ainsi que les boucles) introduisent de nouveaux opérateurs.
Voici le tableau des opérateurs de comparaison.
Opérateur | Signification |
---|---|
< |
Strictement inférieur à |
> |
Strictement supérieur à |
<= |
Inférieur ou égal à |
>= |
Supérieur ou égal à |
== |
Égal à |
!= |
Différent de |
Ainsi, on a 2 < 3
qui est vrai et 3 != 2
qui est aussi vrai.
Essayons de taper quelques expressions avec ces signes sur IRB.
2 > 1
=> true
3 > 6.0
=> false
'Trois' == 'Trois'
=> true
Ces expressions renvoient true
ou false
. Ce sont ce que l’on appelle des booléens. Une variable booléenne ne peut prendre comme valeur que true
ou false
, c’est-à-dire vrai ou faux. Parfait pour faire des conditions.
Notons que la comparaison entre chaînes de caractères se fait suivant l’ordre lexicographique (l’ordre du dictionnaire). Ainsi, 'Trois' > 'Quatre'
renverra true
. L’ordre de Ruby est le suivant : d’abord les chiffres (0, 1, 2… 9), puis les lettres majuscules (A, B… Z), puis les lettres minuscules (a, b… z).
En fait, Ruby compare les caractères des chaînes en utilisant la valeur de leur code UTF-8 (par exemple, 'é' > '#'
vaut true
).
Nous pouvons bien sûr créer des variables de type booléen. Par exemple…
boolean = true
false_boolean = false
Ces booléens nous servent justement à construire nos conditions. Toutes les comparaisons que nous ferons vaudront soit true
, soit false
et il nous faudra juste évaluer cette valeur.
On peut aussi combiner ces opérateurs et faire des comparaisons plus avancées avec trois mots-clés :
and
qui signifie « et » permet d’écrire3 > 2 and 3 < 5
(ce qui est vrai) ;or
qui signifie « ou » permet d’écrire3 > 2 or 2 < 5
(ce qui est vrai) ;not
qui signifie « non », c’est-à-dire la condition contraire, permet d’écrirenot 3 < 2
(ce qui est vrai).
L’on peut remplacer and
par &&
, or
par ||
et not
par !
. En fait, nous allons même privilégier !
&&
et ||
pour les expressions booléennes, conformément aux bonnes pratiques de Ruby.
Mise entre parenthèses
Nous pouvons placer des parenthèses autour de vos comparaisons. Si nous les plaçons autour de toute la condition, cela ne change pas sa valeur. (1 == 2 || 2 == 2)
est strictement équivalent à 1 == 2 || 2 == 2
. Cependant, si nous plaçons des parenthèses autour d’une partie de la condition, sa valeur peut changer. En effet, cela change les priorités. Ainsi :
(1 == 1 || 2 == 3) && 3 == 4
vautfalse
;1 == 1 || (2 == 3 && 3 == 4)
vauttrue
.
Voyons ce qui se passe dans le premier cas.
1 == 1 || 2 == 3
vaut true
, donc c’est équivalent à true && 3 == 4
, avec 3 ≠ 4, donc (1 == 1 || 2 == 3) && 3 == 4
vaut false
.
Dans le deuxième cas maintenant.
2 == 3 && 3 == 4
vaut false
, donc c’est équivalent à 1 == 1 or false
, avec 1 = 1, donc 1 == 1 || (2 == 3 && 3 == 4)
vaut true
.
La structure if-else
La structure if
-else
est la plus simple des structures conditionnelles. On évalue une expression (on regarde si elle vaut true
ou false
) ; si (if
) elle vaut true
, on exécute certaines instructions, sinon (else
), on en exécute d’autres.
Prenons le cas d’un programme qui demande l’âge de l’utilisateur et nous dit s’il est majeur ou mineur. S’il a moins de 18 ans, il est mineur, sinon, il est majeur.
age = gets.chomp.to_i # On récupère une saisie et on la convertit en entier.
if age < 18
print 'Vous êtes mineur.'
else # Sinon…
print 'Vous êtes majeur.'
end
Ici, nous vérifions si la variable age
est inférieure à 18 grâce à <
. Rentrons différents âges inférieurs ou supérieurs à 18 et admirons le travail.
Cette structure conditionnelle se termine toujours par le mot-clé end
. C’est très important, et il ne faut pas l’oublier.
L’indentation n’est pas obligatoire comme en Python. Cependant, il faut quelque chose pour séparer le if condition
des instructions à exécuter. Le retour à la ligne est l’un des moyens de faire cette séparation. Le mot clé then
(« alors ») est l’autre manière de la faire. On peut alors écrire ce code strictement équivalent au précédent.
age = gets.chomp.to_i # On récupère une saisie et on la convertit en entier.
if age < 18 then print 'Vous êtes mineur.' else print 'Vous êtes majeur.' end
Mais nous allons plutôt privilégier la première écriture. Notons de plus qu’il est conseillé d’indenter en utilisant deux espaces. Nous pouvons combiner le then
et le retour à ligne, mais ce n’est pas une pratique conseillée.
Notons que le else
n’est pas obligatoire. Nous pouvons parfaitement écrire ceci.
age = gets.chomp.to_i # On récupère une saisie et on la convertit en entier.
if age < 18
print 'Vous êtes mineur.'
end
Le mot-clé elsif
Si nous avons plus de deux possibilités, nous pouvons compléter notre structure if
-else
avec un elsif
(sinon si). Il permet d’ajouter une autre possibilité à la condition if
. Prenons le code précédent et rajoutons un elsif
.
age = gets.chomp.to_i
if age < 18 # Si âge est inférieur à 18…
print 'Vous êtes mineur.'
elsif age > 80 # Si âge est supérieur à 80…
print 'Vous êtes senior.'
else # Sinon…
print 'Vous êtes majeur et votre âge est inférieur à 80 ans.'
end
On regarde si la première condition est vraie. Si elle est vraie, on affiche que l’utilisateur est mineur, sinon, on regarde la seconde condition, et enfin, on arrive au else
qui s’exécute si aucune des conditions précédentes n’est vraie.
Nous pouvons utiliser autant de elsif
que nous voulons.
Ce n’est vraiment pas compliqué à utiliser. La seule subtilité est que les remarques que nous avons tenues à propos du if
sont aussi valables pour le elsif
: là encore, le retour à la ligne est obligatoire à moins que nous n’utilisions le mot-clé then
.
Notons qu’il existe une façon plus concise d’écrire un if
.
age = gets.chomp.to_i
print 'Vous êtes majeur.' if age >= 18
Dans ce cas, il n’y a pas de end
et l’instruction à exécuter doit être unique. Cependant, nous pouvons placer plusieurs instructions en utilisant le point-virgule et des parenthèses de cette manière.
age = gets.chomp.to_i
(print 'Vous êtes majeur.'; print 'Peut-être même que vous êtes senior.') if age >= 18
Cette notation est conseillée pour les conditions sur une seule ligne, en particulier s’il n’y a qu’une seule instruction à exécuter et qu’elle est simple. Cependant, si la condition —- ou même l’instruction —- est trop compliquée, nous allons privilégier un if
classique.
La structure unless
La structure unless
fonctionne exactement de la même manière que if
, et est en fait la condition contraire de if
. Avec unless
, les instructions sont toujours exécutées sauf lorsque la condition est vérifiée. On a donc unless (condition)
qui est équivalent à if !(condition)
. Pour l’âge, on peut donc écrire ce programme.
age = 19
unless age < 18
print 'Vous êtes majeur.'
else
print 'Vous êtes mineur.'
end
Là encore, nous pouvons utiliser la structure condensée.
print 'Vous êtes majeur.' unless age < 18
Une bonne pratique consiste à privilégier unless
pour les conditions négatives, c’est-à-dire que nous allons préférer écrire ce genre de code.
# Mauvais code.
if !condition
# Instructions.
end
# Bon code.
unless condition
# Instructions.
end
Cependant, nous n’allons pas utiliser unless
avec else
, mais préférer réécrire la condition en changeant le unless
par un if
et en inversant les conditions.
# Mauvais code.
unless condition
# Autres instructions.
else
# Instructions.
end
# Bon code.
if condition_inverse
# Instructions.
else
# Autres instructions.
end
Hormis cela, les bonnes pratiques pour unless
sont les mêmes que celles pour if
.
La structure case-when
La structure case
-when
est une autre structure de condition. Elle permet de tester une suite de conditions sur une variable. Si la variable vaut telle valeur, alors fais ceci, sinon, si elle vaut telle autre valeur, alors fais cela… Par exemple, écrivons un programme qui demande à l’utilisateur d’entrer « Un », « Deux » ou « Trois » et qui affiche la valeur numérique du nombre entré.
number = gets.chomp
case number # On teste la valeur de nombre.
when 'Un' # Si c’est "Un"…
print 1
when 'Deux' # Sinon, si c’est "Deux"…
print 2
when 'Trois' # Sinon, si c’est "Trois"…
print 3
end
Là encore, il y a un end
. Il est aussi obligatoire.
Notons que nous pouvons rajouter un else
pour faire quelque chose si aucun des cas testés n’est vérifié.
number = gets.chomp
case number
when 'Un'
print 1
when 'Deux'
print 2
when 'Trois'
print 3
else
print 'La saisie n’est pas bonne.'
end
Si la saisie de l’utilisateur n’est ni « Un », ni « Deux », ni « Trois », alors on affiche « La saisie n’est pas bonne. ».
Notons que nous pouvons écrire le when
et l’action à effectuer sur une seule ligne en utilisant le mot-clé then
. Ainsi, le code qui suit est strictement équivalent à celui que nous avons écrit plus haut.
number = gets.chomp
case number
when 'Un' then print 1
when 'Deux' then print 2
when 'Trois' then print 3
else print 'La saisie n’est pas bonne.'
end
Les intervalles
Cependant, là où case
s’avère vraiment utile, c’est qu’il permet de tester si une valeur est dans un intervalle.
En Ruby, nous allons noter un intervalle x..y
, qui représente l’intervalle (donc et sont inclus). Pour voir comment nous pouvons utiliser cela, prenons l’exemple d’un programme qui vérifierait l’admission ou la mention selon une note à un examen. Dans notre cas, avoir en dessous de 6 est un échec, au-dessus de 12 la mention « Assez bien », de 14 la mention « Bien » et de 16 la mention « Très bien ».
Faire ce programme avec des if
et des else
serait long et contraignant. La structure case
permet de simplifier les choses en offrant plusieurs choix.
mark = 18 # Nous pouvons modifier la note et voir ce qu’on obtient.
case mark
when 0..6
print 'Vous n’avez pas réussi l’examen.'
when 6..12
print 'Vous avez réussi l’examen.'
when 12..14
print 'Vous avez réussi l’examen avec mention « Assez bien ».'
when 14..16
print 'Vous avez réussi l’examen avec mention « Bien ».'
when 16..20
print 'Vous avez réussi l’examen avec mention « Très bien ».'
else
print 'La note entrée est incorrecte.'
end
Ça aurait été vraiment embêtant de faire tout ça avec des if
et des else
.
Les intervalles peuvent aussi se faire avec des valeurs flottantes. Ainsi, nous pouvons choisir d’attribuer la mention when 16.5..20
.
Les conditions ternaires
Dans plusieurs langages, il y a ce que l’on appelle des conditions ternaires. Elles sont un moyen condensé d’écrire des conditions. Voici le schéma qu’elles suivent.
condition ? (si true) : (sinon)
Ce n’est pas aussi impressionnant que ça en a l’air. Il faut bien sûr s’habituer à la syntaxe, mais une fois celle-ci assimilée, il faut s’exercer pour réussir à la maîtriser.
age = 19
(age < 18) ? (print 'Mineur') : (print 'Majeur')
Et on peut même utiliser des conditions ternaires imbriquées pour obtenir du else if
.
age = 19
(age < 18) ? (print 'Mineur') : (age < 80 ? (print 'Majeur') : (print 'Senior'))
Là c’est plus compliqué, non ? Il faut bien prendre le temps de comprendre le code.
Les conditions ternaires sont rares dans d’autres langages, mais sont assez appréciées en Ruby pour leur compacité. Ainsi, nous aurons peut-être l’occasion de les croiser dans un code. En fait, la bonne pratique en Ruby est de privilégier les conditions ternaires si la condition est de la forme if
-then
-else
-end
c’est-à-dire dans les cas comme celui que nous avons traité.
Cependant, il faut éviter d’imbriquer plusieurs conditions ternaires et utiliser une structure if
ou unless
dans ce cas-là. De même, il faut privilégier les structures if
et unless
si la condition est sur plusieurs lignes.
Exercices
Voilà une nouvelle série d’exercices.
Exercice 1
Le premier exercice est encore une fois plutôt simple : demandons à l’utilisateur d’entrer trois nombres, puis affichons le plus grand des trois nombres.
Correction.
Voici notre correction. Bien sûr, on peut tout à fait avoir un code différent. On a été malin : on compare le nouveau nombre entré au maximum des nombres déjà entrés.
puts 'Entrez trois nombres.'
number = gets.chomp.to_i
max = number
number = gets.chomp.to_i
max = number if number > max
number = gets.chomp.to_i
max = number if numbet > max
print max
Maintenant, modifions ce programme pour qu’il affiche les trois nombres triés par ordre croissant.
Correction.
Pour faire cela, nous allons demander nos trois nombres, les trier, et les afficher ensuite.
puts 'Entrez trois nombres.'
number1 = gets.chomp.to_i
number2 = gets.chomp.to_i
number3 = gets.chomp.to_i
if number1 > number2 # Si number1 > number2, on les échange.
tmp = number1
number1 = number2
number2 = tmp
end
if number2 > number3 # Si number2 > number3, on les échange.
tmp = number2
number2 = number3
number3 = tmp
# l'ancien number3 était plus petit que l'ancien number2, alors il peut
# être plus petit que number 1.
if number1 > number2
tmp = number1
number1 = number2
number2 = tmp
end
end
puts number1, number2, number3
Pour bien comprendre l’idée qui est mise en place, il faut prendre un papier et un crayon.
Exercice 2
Cet exercice est plus un mini TP. Nous devons demander une année à l’utilisateur et déterminer si elle est ou non bissextile. Donc, il nous faut savoir la condition suivant laquelle une année peut être qualifiée de bissextile.
Une année est dite bissextile si elle est divisible par 400 ou si elle est divisible par 4 et non divisible par 100.
Un peu d’aide…
Une question reste problématique : comment tester si un nombre a
est multiple d’un nombre b
?
En fait, il suffit de tester le reste de la division entière de b
par a
. Si ce reste est nul, alors a
est un multiple de b
.
5 % 2 # 5 n’est pas un multiple de 2.
=> 1
8 % 2 # 8 est un multiple de 2.
=> 0
Il suffit d’appliquer cette méthode à notre cas.
Correction.
Voici une correction possible (d’autres code peuvent aussi fonctionner).
puts 'Entrez une année : '
year = gets.chomp()
year = année.to_i()
if year % 400 == 0
puts 'L’année est bissextile.'
elsif year % 4 == 0 && year % 100 != 0
puts 'L’année est bissextile.'
else
puts 'L’année n’est pas bissextile.'
end
On peut le simplifier.
puts 'Entrez une année : '
année = gets.chomp()
année = année.to_i()
if year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)
puts 'L’année est bissextile.'
else
puts 'L’année n’est pas bissextile.'
end
Exercice 3
Nous allons maintenant devenir commerçants. Notre objectif : demander à l’utilisateur de rentrer le prix HT d’un objet et son code (compris entre 1 et 3), et calculer le prix TTC de l’objet sachant que le code 1 correspond à une TVA de 20 %, le code 2 à une TVA de 10 % et le code 3 à une TVA de 5.5 % (on considère que la seule taxe est la TVA).
Nous allons donc devoir manier des pourcentages.
Correction.
On va déclarer trois constantes correspondant aux trois taux de TVA et les utiliser pour nos calculs.
TVA1 = 20.0
TVA2 = 10.0
TVA3 = 5.5
print 'Entrez le prix de votre produit : '
priceHT = gets.chomp.to_f
print 'Entrez le code de votre produit : '
code = gets.chomp.to_i
if code == 1
priceTTC = priceHT + TVA1 / 100 * priceHT
elsif code == 2
priceTTC = priceHT + TVA2 / 100 * priceHT
elsif code == 3
priceTTC = priceHT + TVA3 / 100 * priceHT
end
case code
when 1..3
print "Le prix TTC de votre produit est #{priceTTC}."
else
print 'Votre code n’est pas valide.'
end
Le code peut être raccourci, par exemple de cette manière.
print 'Entrez le prix de votre produit : '
priceHT = gets.chomp.to_f
price 'Entrez le code de votre produit : '
code = gets.chomp.to_i
if code == 1
print "Le prix TTC de votre produit est #{priceHT * 1.2}."
elsif code == 2
print "Le prix TTC de votre produit est #{priceHT * 1.1}."
elsif code == 3
print "Le prix TTC de votre produit est #{priceHT * 1.055}."
else
print 'Votre code n’est pas valide.'
end
Voilà, le chapitre sur les conditions est terminé. Maintenant, nos programmes n’ont plus un comportement linéaire, mais peuvent faire une action suivant la valeur d’une variable.
- Ruby dispose d’opérateurs de comparaison (supérieur, inférieur, différent, etc.) que l’on peut combiner avec les symboles
||
,&&
et!
. - Une expression faite avec ces symboles s’appelle une expression booléenne et vaut soit
true
soitfalse
. - On peut exécuter certaines instructions en fonction de la valeur d’un booléen en utilisant des structures conditionnelles (
if
-elsif
-else
ouunless
-else
par exemple). - La structure
case
-when
permet de tester une suite de conditions sur une même variable. Elle permet également de tester si une variable appartient à un intervalle donné. - Les conditions ternaires sont un moyen condensé d’écrire des conditions et sont assez appréciées en Ruby.