Un corrigé pédagogique pour comprendre et justifier vos réponses. Les conseils de rédaction ne constituent pas un barème officiel détaillé.
Application
Consommation d’eau, fuite nocturne et moyenne glissante
Un compteur fournit des mesures triées par jour et heure croissants. Chaque dictionnaire contient jour au format AAAA-MM-JJ, heure au format HH: MM et les volumes entière chaude et froide consommés depuis la mesure précédente. Le total est leur somme. On doit distinguer un jour sans mesure d’un jour avec consommation nulle, détecter trois mesures nocturnes consécutives positives puis lisser une série sans changer sa longueur.
| Heure | Exemple sans fuite | Exemple avec fuite |
|---|---|---|
| 00:00 | 5 | 2 |
| 01:00 | 3 | 1 |
| 02:00 | 0 | 1 |
| 03:00 | 3 | 0 |
| 04:00 | 0 | 0 |
| 05:00 | 0 | 0 |
Le dossier comporte le sujet et les fichiers listés dans les téléchargements. Les codes de départ sont reproduits ci-dessous. Travaillez sur une copie. Les appels professeur signalés dans les questions servent à présenter votre démarche ; vous pouvez aussi demander de l’aide en cas de difficulté.
Code fourni : analyse_eau.py
donnees = [
{"jour": "2025-02-04", "heure": "00:00", "chaude": 2, "froide": 3},
{"jour": "2025-02-04", "heure": "01:00", "chaude": 1, "froide": 2},
{"jour": "2025-02-04", "heure": "02:00", "chaude": 0, "froide": 0},
{"jour": "2025-02-04", "heure": "03:00", "chaude": 0, "froide": 0},
{"jour": "2025-02-04", "heure": "04:00", "chaude": 0, "froide": 1},
{"jour": "2025-02-04", "heure": "05:00", "chaude": 0, "froide": 0},
{"jour": "2025-02-04", "heure": "06:00", "chaude": 4, "froide": 6},
{"jour": "2025-02-04", "heure": "07:00", "chaude": 6, "froide": 8},
{"jour": "2025-02-05", "heure": "00:00", "chaude": 0, "froide": 0},
{"jour": "2025-02-05", "heure": "01:00", "chaude": 1, "froide": 1},
{"jour": "2025-02-05", "heure": "02:00", "chaude": 1, "froide": 1},
{"jour": "2025-02-05", "heure": "03:00", "chaude": 1, "froide": 1},
{"jour": "2025-02-05", "heure": "04:00", "chaude": 0, "froide": 0},
{"jour": "2025-02-05", "heure": "05:00", "chaude": 0, "froide": 0},
]
# -----------------------------
# Fonctions à compléter
# -----------------------------
def total_conso(donnees, jour):
# À compléter
pass
def fuite_possible(donnees, jour):
# À compléter
pass
# -----------------------------
# Fonction fournie (erronée)
# -----------------------------
def lissage_conso(valeurs):
"""
Calcule une moyenne glissante sur les valeurs.
Pour chaque valeur, on calcule la moyenne avec ses voisins.
"""
lisse = []
for i in range(len(valeurs)):
if i == 0:
m = (valeurs[i] + valeurs[i+1]) / 2
elif i == len(valeurs)-1:
m = (valeurs[i-1] + valeurs[i]) / 2
else:
m = (valeurs[i-1] + valeurs[i] + valeurs[i+1]) / 2
lisse.append(m)
return lisse
# -----------------------------
# Espace pour les tests
# -----------------------------
def test_lissage():
# À compléter : écrire au moins 3 assertions (assert) avec des listes
# de différentes tailles pour révéler les erreurs de la fonction
pass
Question 1
#Écrire total_conso(donnees, jour), qui renvoie la somme de l’eau chaude et froide de ce jour. Renvoyer None si aucune mesure n’existe. Le 04 février 2025 doit donner 33 ; le 25 décembre 2025 ne possède pas de mesure.
Indice
Un total nul ne prouve pas l’absence de mesure.
Comprendre la correction
def total_conso(donnees, jour):
total = 0
trouve = False
for mesure in donnees:
if mesure['jour'] == jour:
trouve = True
total += mesure['chaude'] + mesure['froide']
return total if trouve else Noneassert total_conso(donnees,'2025-02-04') == 33
assert total_conso(donnees,'2025-12-25') is None
assert total_conso([{'jour':'x','heure':'00:00','chaude':0,'froide':0}], 'x') == 0Le booléen trouve distingue absence et zéro. Tester seulement total==0 confondrait ces deux situations. La somme du 04 février vaut 5+3+0+0+1+0+10+14=33 litres.
Question 2
#Écrire fuite_possible(donnees, jour). Une fuite est suspectée s’il existe au moins trois mesures consécutives entre 00:00 et 05:00 inclus dont chaque consommation totale est positive. Renvoyer True ou False.
PythonDistinguer trois consommations de trois consommations consécutivesÉcrivez votre solution et mettez-la à l’épreuve
Écrivez fuite_possible(donnees, jour). Les mesures horaires sont triées. Cherchez au moins trois mesures consécutives entre 00:00 et 05:00 inclus, le jour demandé, dont chacune a chaude + froide > 0. Un zéro interrompt la série. Les tests conservent le contrat d’une série horaire régulière ; ils ne demandent pas de reconstituer des mesures manquantes.
def fuite_possible(donnees, jour):
# À vous de jouer
pass
Les cas de test proposés :
- Trois premières heures positives : La série atteint trois sans devoir examiner toute la nuit.
- Trois valeurs positives dispersées : Le zéro remet la longueur de série à zéro.
- Série terminant à 05:00 : 05:00 est inclus et l’eau froide compte aussi.
- 06:00 ne complète pas la série : La plage de détection s’arrête après la mesure de 05:00.
- Le jour est un filtre : Une fuite d’un autre jour ne répond pas à la question posée.
- Aucune mesure : Aucune série ne peut commencer.
Indice
Conserver le nombre de positifs consécutifs, pas leur nombre total.
Comprendre la correction
def fuite_possible(donnees, jour):
suite = 0
for mesure in donnees:
if mesure['jour'] == jour and '00:00' <= mesure['heure'] <= '05:00':
if mesure['chaude'] + mesure['froide'] > 0:
suite += 1
if suite >= 3:
return True
else:
suite = 0
return Falsesuite mesure la longueur de la série positive en cours. Un zéro interrompt cette série et remet le compteur à zéro. Trois mesures positives dispersées ne suffisent pas. Comme les heures sont au format fixe HH: MM, leur comparaison lexicographique respecte l’ordre chronologique. Le sujet parle de mesures consécutives dans une série horaire triée ; si des relevés horaires peuvent manquer, il faudrait en plus contrôler l’écart d’une heure entre relevés, ce qui est une extension du contrat.
assert not fuite_possible(donnees,'2025-02-04')
assert fuite_possible(donnees,'2025-02-05')
assert not fuite_possible([], '2025-02-05')Sur la suite 5, 3, 0, 3, 0, 0, le compteur prend successivement les valeurs 1, 2, 0, 1, 0, 0 : aucune série n’atteint 3. Sur 2, 1, 1, 0, 0, 0, il atteint 3 au troisième relevé et permet un retour immédiat. Cette trace montre pourquoi compter simplement le nombre de relevés positifs serait insuffisant : la première série contient aussi trois valeurs positives, mais séparées par des zéros. Le test doit donc inclure ces deux formes, pas seulement une suite entièrement positive.
Question 3
#La fonction lissage_conso moyenne les voisins : deux valeurs aux extrémités et trois à l’intérieur. Expliquer le résultat incorrect sur [10,20,30,40,50] et proposer une correction.
PythonLisser sans réutiliser une valeur déjà lisséeÉcrivez votre solution et mettez-la à l’épreuve
Corrigez lissage_conso(valeurs) : chaque case intérieure devient la moyenne de ses deux voisines et d’elle-même ; les extrémités moyennent deux valeurs. Pour zéro ou une valeur, renvoyez une copie inchangée, comme le cas limite de la question 4. Conservez la liste source.
def lissage_conso(valeurs):
# À vous de jouer
pass
Les cas de test proposés :
- Série de l’énoncé : Les cases intérieures divisent par trois ; les extrémités par deux.
- Un pic isolé : Lire les résultats précédents au lieu des valeurs source déformerait la répartition.
- Une constante reste constante : Une moyenne de valeurs identiques doit conserver cette valeur.
- Deux valeurs : Les deux cases sont des extrémités.
- Une seule valeur et liste vide : Aucun voisin inexistant ne doit être lu.
- Conserver l’original : Le calcul s’appuie entièrement sur la série originale.
Indice
Compter les termes du numérateur de chaque branche.
Comprendre la correction
La branche des éléments intermédiaires additionne trois valeurs puis divise par 2. Elle produit 30,45,60 au lieu de 20,30,40. Les extrémités sont correctes. La sortie attendue est [15.0,20.0,30.0,40.0,45.0]. Voici la version corrigée, incluant le cas limite de la question 4 :
def lissage_conso(valeurs):
if len(valeurs) <= 1:
return valeurs.copy()
lisse = []
for i in range(len(valeurs)):
if i == 0:
m = (valeurs[0] + valeurs[1]) / 2
elif i == len(valeurs) - 1:
m = (valeurs[i-1] + valeurs[i]) / 2
else:
m = (valeurs[i-1] + valeurs[i] + valeurs[i+1]) / 3
lisse.append(m)
return lisseOn lit toujours la liste originale et on écrit dans une nouvelle liste. Modifier les valeurs source au fil du calcul ferait dépendre les moyennes suivantes des résultats déjà lissés.
Le dénominateur exprime combien de mesures ont participé à la moyenne. À une extrémité, on n’a que deux valeurs ; à l’intérieur, on en a trois. Pour une série constante, chaque résultat doit rester cette constante : par exemple [12, 12, 12] doit rester [12, 12, 12]. Ce test est très efficace contre le mauvais diviseur, car la version fournie produit 18 au centre. Il complète le test croissant de l’énoncé et illustre une propriété générale du lissage.
Question 4
#Identifier un autre cas limite que les listes de deux valeurs, non traité correctement par lissage_conso, puis proposer une solution.
Comprendre la correction
Avec une seule valeur, la première branche accède à valeurs[1] : cet indice n’existe pas. La convention naturelle est de conserver la valeur unique. La liste vide était déjà rendue vide par la boucle ; la garde de la correction traite ces deux tailles explicitement et renvoie une copie.
def test_lissage():
assert lissage_conso([]) == []
assert lissage_conso([8]) == [8]
assert lissage_conso([10,20]) == [15.0,15.0]
assert lissage_conso([10,20,30,40,50]) == [15,20,30,40,45]
origine = [10,20,30]
resultat = lissage_conso(origine)
assert origine == [10,20,30] and resultat is not origineDistinguer les cas limitesUn atelier pour expérimenter
Choisissez une réponse puis confrontez votre intuition à l’explication. Vous pouvez modifier vos choix.
Lire les réponses et leurs explications
- Une seule valeur 8 doit être lissée en…
[8]. La seule mesure disponible est conservée.
- Pourquoi écrire dans une nouvelle liste ?
Pour ne pas réutiliser des valeurs déjà lissées.. Toutes les moyennes doivent utiliser les mesures originales.
Appuyez votre explication sur les valeurs et les conditions exactes du programme.
Chercher une série de trois consommationsUn atelier pour expérimenter
Activez ou désactivez les six relevés nocturnes. Le tableau suit le compteur de mesures positives consécutives. Une case active représente 1 litre, une case inactive 0 litre.
Lire le résultat de l’expérience initiale
Fuite possible selon le critère du sujet.
Un zéro annule la série en cours. Le signal est une suspicion définie par le modèle, pas un diagnostic certain.
| Heure | Litres | Longueur de la série |
|---|---|---|
| 00:00 | 1 | 1 |
| 01:00 | 1 | 2 |
| 02:00 | 1 | 3 |
| 03:00 | 0 | 0 |
| 04:00 | 0 | 0 |
| 05:00 | 0 | 0 |
Un compteur de consécutivité doit être remis à zéro à chaque rupture.
Revoir les notions de cet exercice
Du sujet à la méthode
Votre prochaine séance de révision
- Distinguer une observation nulle d’une observation absente.
- Tester les extrémités d’une liste avant de généraliser le calcul.
Retrouver ces notions dans d’autres sujets
Toutes les annales de NSI · Le guide pour préparer le bac NSI 2027
Énoncé : sujet 26_BCG_NSI_10 (PDF). Corrigé et explications pédagogiques proposés par Sofien.
