E06 - Nombres impairs⚓︎
Le problème
Proposition 1⚓︎
🐍 Script Python
def nb_impairs(n: int, m: int) -> str:
"""Cette fonction prend en paramètre deux entiers et affiche dans un ordre croissant tous les nombres impairs se trouvant entre ces deux entiers inclus.
>>> 42 51
43 45 47 49 51
"""
liste_nb_impairs = []
for x in range(m - n + 1):
if n % 2 == 0:
pass
else:
liste_nb_impairs.append(n)
n += 1
formatage = " ".join([repr(x) for x in liste_nb_impairs])
return formatage
# tests
import doctest
doctest.testmod()
# Entrée
n, m = map(int, input().split())
# Sortie
print(nb_impairs(n, m))
- Annotations de type cohérentes, mais on préfère ici le renvoi d'une liste.
- doctest à revoir.
for x in range(m - n + 1):
correct, mais à justifier.- On peut éviter le
else pass
... - On peut éviter de calculer un modulo à chaque tour de boucle.
- Ici,
repr
etstr
sont identiques.
Proposition 2⚓︎
🐍 Script Python
def nombres_impairs(début : int , fin : int) -> list:
""" Recherche sur un intervalle tout les nombres impairs et les renvoies de manière récursive
>>> nombres_impairs(23,33)
23 25 27 29 31 33
"""
if début > fin:
return
if début % 2 == 1:
print(début,end=" ")
return nombres_impairs(début+1,fin)
else:
return nombres_impairs(début+1,fin)
# tests
import doctest
doctest.testmod()
# Entrée
début,fin = map(int,input().split())
# Sortie
nombres_impairs(début,fin)
- doctest correct, mais docstring incorrecte : la fonction affiche, elle ne renvoie pas les nombres impairs.
- Cette version récursive est intéressante.
- Problème : cette version affiche une espace en trop à la fin. C'est souvent accepté par les juges en ligne, mais pas toujours !!!
Proposition 3⚓︎
🐍 Script Python
nombre_1, nombre_2 = map(int, input().split(" "))
if nombre_1 % 2 == 0:
nombre_1 += 1
liste_nombres_impairs = [nombre_impair for nombre_impair in range(nombre_1, nombre_2+1, 2)]
print(" ".join(str(nombre) for nombre in liste_nombres_impairs))
- On attendait une fonction.
[nombre_impair for nombre_impair in range(nombre_1, nombre_2+1, 2)]
à remplacer par :list(range(nombre_1, nombre_2+1, 2))
- De même, utiliser
map(str, liste_nombres_impairs)
dans lejoin
. Voir le corrigé.
Proposition 4⚓︎
🐍 Script Python
def impairs(premier_entier: int, deuxieme_entier: int) -> int:
"""Renvoie les nombres impairs entre deux données.
>>> impairs(42,51)
43 45 47 49 51
"""
for x in range (premier_entier, deuxieme_entier+1):
if x & 1 == 1:
print(x, end=" ")
# Test
import doctest
doctest.testmod()
# Entrées
premier_entier, deuxieme_entier = map(int, input().split())
if not(1 <= premier_entier < deuxieme_entier <= 200):
raise ValueError('Les nombres sont soit gros grand, soit le premier nombre et plus grand que le deuxième.')
# Sortie
impairs(premier_entier, deuxieme_entier)
- doctring et annotation de type de sortie fausses ; la fonction renvoie
None
et non un entier.- On préfère ici l'affichage en dehors de la fonction.
- Aérer le doctest.
- Aérer
deuxieme_entier+1
; toujours quand la variable comporte plus d'une lettre. raise
inutile dans cette situation.
Proposition 5⚓︎
🐍 Script Python
def cherche_impair_entre_nb(premier_entier: int, deuxième_entier: int):
""" cherche des nombre impair entre deux nombre et
affiche la liste de c'est nombre nombre trouver
>>> cherche_impair_entre_nb(42, 51)
[43, 45, 47, 49, 51]
"""
if premier_entier > deuxième_entier:
raise ValueError("il faux que la première entré < deuxième entré")
else:
liste_impair = []
for x in range(premier_entier, deuxième_entier + 1): #deuxième_entier + 1 car il est inclu
if x%2 == 0:
None
else:
liste_impair.append(x)
return liste_impair
import doctest
doctest.testmod()
premier_entier, deuxième_entier = map(int, input().split())
"""
on sait que le premier indise est toujour inférieur au deuxième
donc on sera pas oubliger de faire un test pour voir si c'est vrai
mais la on va quand même le faire
"""
for v in cherche_impair_entre_nb(premier_entier, deuxième_entier):
print(v, end=' ')
- La fonction renvoie une liste ; c'est bien. Cependant la docstring annonce le contraire, qu'elle l'affiche !
- doctring à revoir avec un correcteur orthographique et grammatical. On attend peu de phrases en NSI, autant les rendre les plus simples et justes. Un effort est apprécié.
- Bon doctest, mais à aérer.
raise
inutile dans cette situation.# deuxième_entier inclus
est un commentaire encore plus court, il est utile, c'est bien comme rappel.- Le
None
avecelse
sont inutiles. - Le dernier commentaire est peu clair. Était-il utile ?
- Pour l'affichage,
" ".join(...)
est préférable. Ici, il y aura une espace en trop à la fin.
Proposition 6⚓︎
🐍 Script Python
"""Cette algorithme deux entiers en paramètres, et il affiche, dans l'ordre croissant, tous les nombres impairs se trouvant entre ces deux entiers.
exemple d'entrée : 42 51
exemple de sortie : 43 45 47 49 51
"""
# tests
import doctest
doctest.testmod()
# Entrée
nb_1, nb_2 = map(int, input().split())
# Algorithme
nb_impaire=[x for x in range(nb_1, (nb_2+1)) if x%2] #écriture fonctionnelle
résultat_conversion = ' '.join(str(elem) for elem in nb_impaire) #Conversion d'une liste d'entiers en chaine de caractère en utilisant join()
# Sortie
print(résultat_conversion)
- « Cette algorithme deux entiers en paramètres,(...) » (sic)
- Il manque le verbe prendre.
- Algorithme est masculin, donc « Cet algorithme prend ... ».
- En fait, ce serait plutôt « Ce programme prend ... ».
- Il manque la précision utile de l'inclusion des bornes.
- Aérer de chaque côté du
=
. (Sauf pour les paramètres par défaut de fonction.) - Quitte à utiliser un style fonctionnel, autant l'utiliser efficacement :
[x for x in chose]
devientlist(chose)
.' '.join(str(elem) for elem in nb_impaire)
devient' '.join(map(str, nb_impaire))
.
Proposition 7⚓︎
🐍 Script Python
# 0- Coeur du programme
def nombres_impairs_entre(nombre1: int, nombre2: int) -> str:
""" Renvoie tous les nombres impairs se trouvant entre nombre1 et nombre2 dans l'ordre croissant.
>>> nombres_impairs_entre(1, 3)
'1 3'
>>> nombres_impairs_entre(42, 51)
'43 45 47 49 51'
"""
entiers_impairs = ""
if nombre1 % 2 == 1:
# Si nombre1 est impair, on renvoie tous les nombres entre nombre1 et nombre2 inclus avec un pas de 2
for x in range(nombre1, nombre2+1, 2):
entiers_impairs += str(x) + " "
else:
# Si nombre1 est pair, on renvoie tous les nombres entre nombre1 exclus et nombre2 inclus avec un pas de 2
for x in range(nombre1+1, nombre2+1, 2):
entiers_impairs += str(x) + " "
return entiers_impairs.strip()
#Variante:
#entiers_impairs = [str(x) for x in range(nombre1,nombre2+1) if x%2 == 1]
#return " ".join(entiers_impairs)
# 1- Tests
import doctest
doctest.testmod()
# 2- Lecture de l'entrée
nombre1, nombre2 = map(int,input().split())
# 3- Appel de la fonction / Sortie
print(nombres_impairs_entre(nombre1, nombre2))
- On attendait plutôt une fonction qui renvoie la liste, et non la chaine.
- L'affichage comporte ici une espace en trop à la fin.
- Il y a deux bouts de code qui se ressemblent, signe qu'on aurait pu le factoriser.
Proposition 8⚓︎
🐍 Script Python
def nb_impairs(début : int, fin : int) -> int :
""" Renvoie, dans l'ordre croissant,
tous les entiers impairs se trouvant entre les nombres 'début' et 'fin'.
>>> début, fin = 42 51
>>> nb_impairs(début, fin)
43 45 47 49 51
"""
for nb in range (début, fin + 1) :
if nb % 2 != 0 : #si nb est impair
print(nb, end=" ")
# tests
import doctest
doctest.testmod()
# Entrée
début, fin = map(int, input().split())
assert 1 <= début < fin <= 200
# Sortie
nb_impairs(début, fin)
- La fonction ne renvoie pas, mais elle affiche ; ce n'est pas pareil.
- L'annotation de sortie est fausse, la fonction renvoie
None
. - Très bon doctest, mais ici ce serait utile d'en avoir 4, pour chaque cas de parité.
- Le
assert
est inutile dans ce genre de situation.
Corrigé du professeur⚓︎
Version basique⚓︎
🐍 Script Python
"""
author : Franck CHAMBON
problem: https://prologin.org/train/2003/semifinal/nombres_impairs
"""
def nombres_impairs(n: int, m: int) -> list[int]:
"""Renvoie la liste des nombres impairs entre `n` et `m` inclus.
>>> nombres_impairs(42, 51)
[43, 45, 47, 49, 51]
>>> nombres_impairs(42, 52)
[43, 45, 47, 49, 51]
>>> nombres_impairs(43, 51)
[43, 45, 47, 49, 51]
>>> nombres_impairs(43, 52)
[43, 45, 47, 49, 51]
"""
impairs = []
i = n
if i % 2 == 0:
i += 1
# i est désormais impair
while i <= m:
impairs.append(i)
i += 2
return impairs
import doctest
doctest.testmod()
n, m = map(int, input().split())
impairs = nombres_impairs(n, m)
print(" ".join(map(str, impairs)))
- On a mis 4 doctest, un pour chaque type suivant la parité de
n
etm
. - Le
while
est un peu plus rudimentaire qu'une boucle avecfor
.
Version fonctionnelle⚓︎
1 ligne. Non recommandée, mais à but pédagogique.
n - (n&1)
, c'estn
s'il est pair, sinonn-1
; le résultat est pair, juste inférieur ou égal àn
.n - (n&1) + 1
, c'est doncn
s'il est impair, sinonn+1
; le résultat est impair, juste supérieur ou égal àn
.
🐍 Script Python
def nombres_impairs(n: int, m: int) -> list[int]:
return list(range(n - (n&1) + 1, m + 1, 2))
Version récursive⚓︎
N'est pas efficace, mais correcte.
🐍 Script Python
def nombres_impairs(n: int, m: int) -> list[int]:
if n > m:
return []
elif n % 2 == 0:
return nombres_impairs(n + 1, m)
else:
return [n] + nombres_impairs(n + 2, m)
# n + 2 sera le prochain nombre impair
Variante de l'affichage⚓︎
Avec unpack ; ceci est hors programme.
🐍 Script Python
print(*impairs)