Parcourir, sommer, compter
Sommer, trouver le minimum et le maximum, compter des occurrences.
Objectifs
À la fin de cette leçon, vous saurez :
- utiliser le motif accumulateur, socle de presque tous les algorithmes de parcours ;
- écrire somme, minimum, maximum et comptages sans bibliothèque, avec traces à la main ;
- choisir la bonne valeur initiale selon l'opération (élément neutre) ;
- traiter proprement le cas du tableau vide.
🔗 Pour vous rafraîchir la mémoire : du problème à l'algorithme · conditions et boucles
L'accumulateur : LE motif central du chapitre
Presque tous les algorithmes de ce chapitre suivent un même squelette en quatre temps :
let total = 0; // 1. accumulateur initialisé (valeur neutre)
for (const n of nombres) { // 2. parcours complet des données
total += n; // 3. accumulation (éventuellement sous condition)
}
// 4. exploitation : total contient le résultat
Ce motif « initialise → parcourt → accumule » couvre les sommes, les comptages, les minima/maxima, les recherches, les constructions de chaînes. Apprenez le squelette une fois ; chaque algorithme n'en est qu'une instanciation.
Suivons-le à la main sur [4, 8, 15] — l'exercice mental qui rend tout évident :
départ : total = 0
après 4 : total = 4
après 8 : total = 12
après 15 : total = 27 ← boucle finie
résultat : 27
Rien de magique : une case qui grossit au fil des visites.
La somme
function somme(nombres) {
let total = 0;
for (const n of nombres) {
total += n;
}
return total;
}
console.log(somme([4, 8, 15])); // 27
console.log(somme([])); // 0
Observez le tableau vide : la boucle ne tourne jamais, donc total garde sa valeur d'initialisation → 0. Et c'est mathématiquement correct : la somme d'aucun nombre vaut zéro. Quand le cas limite tombe juste « gratuitement », c'est le signe que la valeur initiale a été bien choisie — c'est toute la subtilité de la section suivante.
L'élément neutre : la bonne valeur de départ
Pourquoi 0 pour une somme ? Parce que x + 0 = x : ajouter zéro ne change rien. Cette valeur « transparente pour l'opération » s'appelle l'élément neutre, et chaque opération possède le sien :
| Opération | Élément neutre | Pourquoi |
|---|---|---|
+ (somme) | 0 | x + 0 = x |
× (produit) | 1 | x × 1 = x |
| comptage | 0 | on démarre sans rien compté |
| concaténation de chaînes | "" | texte + rien = texte |
| maximum / minimum | premier élément | voir plus bas |
Choisir la mauvaise valeur initiale est LA source classique de bugs dans ce motif : un produit initialisé à 0 reste éternellement 0. Retenez le tableau, ou le principe (« quelle valeur ne fausse pas mon accumulation ? »).
Minimum et maximum : l'accumulateur candidat
Version manuelle — celle qui compte, car elle se transpose à tout critère (le plus long mot, le salaire le plus élevé...) :
function maximum(nombres) {
if (nombres.length === 0) {
return null; // pas de maximum sans élément !
}
let candidat = nombres[0]; // départ au PREMIER élément
for (const n of nombres) {
if (n > candidat) {
candidat = n; // nouveau champion
}
}
return candidat;
}
console.log(maximum([4, 9, 2])); // 9
console.log(maximum([-5, -2, -9])); // -2
Tracez-le sur [4, 9, 2] :
candidat = 4
voir 9 : 9 > 4 → candidat = 9
voir 2 : 2 > 9 → rien à faire
résultat : 9
Deux vigilances qui font toute la différence :
- Ne JAMAIS partir de
0. Aveclet candidat = 0,maximum([-5, -2])répondrait0— une valeur qui n'existe même pas dans la liste ! Le maximum doit être un élément de l'ensemble : on part donc du premier. (Vous avez déjà rencontré ce piège à l'exercice 9 du chapitre 3.) - Le tableau vide n'a aucun maximum. Répondre
0serait mentir ; on répond explicitementnull, et cette décision fait partie du contrat de la fonction.
Le minimum est strictement symétrique : comparaison inversée (<). À vous de l'écrire dans les exercices.
La version bibliothèque existe aussi — à connaître pour lire le code des autres :
Math.max(4, 8, 15); // 15, mais avec des arguments séparés, pas une liste
Math.max(...nombres); // étalement pour passer la liste — coûteux sur d'énormes listes
Compter : un accumulateur qui avance de 1
Compter des occurrences, c'est la somme sous condition :
function compter(valeurs, cible) {
let compteur = 0;
for (const v of valeurs) {
if (v === cible) {
compteur += 1; // condition remplie → +1
}
}
return compteur;
}
console.log(compter([1, 2, 1, 3, 1], 1)); // 3
console.log(compter([1, 2, 1], 9)); // 0
Le critère peut être n'importe quelle expression booléenne :
function compterPairs(nombres) {
let compteur = 0;
for (const n of nombres) {
if (n % 2 === 0) { // pair/impair, longueur minimale, préfixe...
compteur += 1;
}
}
return compteur;
}
Même squelette que la somme ; seule la règle d'enrichissement change (+1 si critère au lieu de +valeur toujours). Si vous savez écrire l'un, vous savez écrire l'autre.
Variantes du motif : la factorielle
L'accumulateur ne somme pas forcément. La factorielle de n (écrite n!) multiplie tous les entiers de 1 à n : 5! = 1 × 2 × 3 × 4 × 5 = 120. Même motif, opération changée :
function factorielle(n) {
let produit = 1; // élément neutre de × (comme 0 l'est pour +)
for (let i = 2; i <= n; i++) {
produit *= i; // × au lieu de +
}
return produit;
}
console.log(factorielle(5)); // 120
console.log(factorielle(0)); // 1 : la boucle ne tourne pas,
// et 0! = 1 est bien la définition mathématique
Encore une fois, le cas limite tombe juste grâce à la bonne initialisation. Quand votre algorithme « gère » un cas particulier sans ligne supplémentaire, appréciez : c'est souvent le signe d'une conception saine.
Exercice
Écrivez chaque fonction et testez-la sur au moins trois jeux de données dont un tableau vide :
somme(nombres)— déjà vue, refaites-la sans regarder.minimum(nombres)— version manuelle,nullsi vide.compterImpairs(nombres)— nombre d'éléments impairs (attention aux négatifs !).sommePositifs(nombres)— somme des seuls éléments strictement positifs.moyenne(nombres)— moyenne arithmétique ; décidez et documentez le comportement pour une liste vide.plusLongue(chaines)— la plus longue chaîne du tableau ; en cas d'égalité, la première rencontrée.- Trace à la main : déroulez
compter([1, 2, 1, 3], 1)etmaximum([-7, -1, -3])sur papier avant de coder.
Résumé
- Motif universel : initialiser (élément neutre), parcourir, accumuler (souvent sous condition), exploiter.
- Éléments neutres :
0pour +,1pour ×,""pour concaténer, premier élément pour min/max. - Minimum/maximum : jamais de départ à
0; le vide répondnull. - Un compteur est un accumulateur
+1sous condition.
Correction disponibleCherchez d’abord par vous-même.Voir la correction
Correction
Solutions commentées
function minimum(nombres) {
if (nombres.length === 0) return null;
let candidat = nombres[0];
for (const n of nombres) {
if (n < candidat) { // seule différence avec maximum : < au lieu de >
candidat = n;
}
}
return candidat;
}
function compterImpairs(nombres) {
let compteur = 0;
for (const n of nombres) {
if (n % 2 !== 0) { // ≠ 0 plutôt que === 1 : correct pour les négatifs
compteur += 1;
}
}
return compteur;
}
// Détail : en JavaScript, -3 % 2 vaut -1 (signe du dividende).
// Tester « === 1 » raterait les négatifs impairs ; tester « !== 0 » les attrape.
function sommePositifs(nombres) {
let total = 0;
for (const n of nombres) {
if (n > 0) {
total += n;
}
}
return total;
}
// Liste vide ou tout négatif → 0 : cohérent (somme de rien = 0).
function moyenne(nombres) {
if (nombres.length === 0) {
return null; // décision documentée : pas de moyenne sans note
}
return somme(nombres) / nombres.length; // composition : on réutilise somme !
}
function plusLongue(chaines) {
if (chaines.length === 0) return null;
let candidate = chaines[0];
for (const chaine of chaines) {
if (chaine.length > candidate.length) { // STRICTEMENT supérieur :
candidate = chaine; // garde la première en cas d'égalité
}
}
return candidate;
}
Points d'attention relevés
Question 5 : réutiliser somme plutôt que recopier sa boucle est déjà de la composition de fonctions — trois lignes lisibles contre dix lignes dupliquées. Prenez ce réflexe dès maintenant.
Question 6 : le test strictement supérieur (>) implémente la règle « première rencontrée gagne ». Avec >=, ce serait la dernière. Ce genre de micro-décision doit être conscient — et mentionné quand quelqu'un relit votre fonction.
Question 3 : le piège des négatifs (-3 % 2 === -1) est exactement le genre de subtilité qui justifie de toujours tester ses fonctions sur des jeux de données incluant négatifs, zéro et vide — comme demandé en tête d'exercice.