Aller au contenu

E06 - Nombres impairs⚓︎

Le problème

Nombres impairs

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 et str 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 le join. 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 avec else 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] devient list(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 et m.
  • Le while est un peu plus rudimentaire qu'une boucle avec for.

Version fonctionnelle⚓︎

1 ligne. Non recommandée, mais à but pédagogique.

  • n - (n&1), c'est n s'il est pair, sinon n-1 ; le résultat est pair, juste inférieur ou égal à n.
  • n - (n&1) + 1, c'est donc n s'il est impair, sinon n+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)