Maior número ímpar

Aug 19 2020

Peça ao usuário para inserir 10 inteiros e, em seguida, imprimir o maior número ímpar inserido. Se nenhum número ímpar foi inserido, imprima uma mensagem para esse efeito.

Tenho tentado resolver esse problema com o python e acho que descobri uma maneira que cobre todos os casos possíveis, dada a definição matemática de um número ímpar. Para ter certeza, gostaria de verificar se meu código está correto de acordo com seus próprios critérios.

counter = 0
odd = []

while counter < 10:
    x = int(input("Enter a number: "))
    if abs(x)%2 != 0:
        odd.append(x)
    counter += 1

if len(odd) == 0:
    print("No odd number was entered")
else:
    print("The largest odd number is:", max(odd))

Respostas

19 MarioIshac Aug 19 2020 at 07:14

Para seu programa atual, podemos melhorar algumas coisas:

  1. Renomeie oddpara odds(visto que é um list).
  2. Use em not oddsvez de len(odds) == 0(consulte Como verifico se uma lista está vazia? Para saber por que isso é preferido).
  3. Excluir counter. Visto que usamos apenas counterna whilecondição, podemos substituir o todo whilepor for _ in range(10).
  4. Siga o PEP 8 . Por exemplo, usando 4 espaços para cada nível de indentação.

Considerando todas essas mudanças, obtemos:

odds = []

for _ in range(10):
    x = int(input("Enter a number: "))
    if abs(x) % 2 != 0:
        odds.append(x)

if not odds:
    print("No odd number was entered")
else:
    print("The largest odd number is:", max(odds))

Mas também podemos melhorar a eficiência deste programa. No momento, monitoramos todos os números ímpares antes de escolher o máximo. Isso significa que a complexidade do espaço é O (N). Podemos mudar isso para O (1), mantendo o controle do maior número ímpar, assim:

max_odd = None

for _ in range(10):
    x = int(input("Enter a number: "))

    if abs(x) % 2 != 0:
        max_odd = x if max_odd is None else max(max_odd, x)

if max_odd is None:
    print("No odd number was entered")
else:
    print("The largest odd number is: ", max_odd)

Observe que usamos Nonepara significar que nenhum número ímpar foi inserido até agora, caso em que, após a inserção de um número ímpar, definimos max_oddcomo xdiretamente. Caso contrário, definimos max_oddcomo max(max_odd, x).

Para este tipo de programa você não notará o aumento da eficiência devido à redução da complexidade do espaço. Mas aprender a reconhecer onde essas reduções são possíveis permitirá que você veja os mesmos padrões em programas onde isso é importante.

Finalmente, há mais uma coisa que você pode fazer. Se você quiser permitir que o programa continue acumulando números no caso de um stracidentalmente digitado que não possa ser analisado como um número (como ""), podemos usar um try/ exceptenvolvido em um whileassim:

while True:
    try:
        x = int(input("Enter a number: "))
        break
    except ValueError:
        continue

Isso substituiria:

x = int(input("Enter a number: "))

no código original. Isso continuaria solicitando que o usuário digite um strque seja analisável como um intaté que o faça. Como tudo isso está acontecendo na mesma iteração do for, a contagem de números que eles conseguem digitar (10 em nosso caso) não seria reduzida.

6 GZ0 Aug 19 2020 at 08:58

Adicionando à revisão anterior:

  • Quando xé um inteiro, abs(x) % 2é equivalente a x % 2em Python. A saída do operador módulo %tem o mesmo sinal do segundo operando.
  • Ao executar o código fora de um método / classe, é uma boa prática colocar o código dentro de um guarda principal . Veja aqui para mais explicações.

No Python 3.8, o código pode ser encurtado usando o operador de atribuição :=junto com a maxfunção.

if __name__ == "__main__":
    # Number generator
    num_gen = (o for _ in range(10) if (o := int(input("Enter a number: "))) % 2 != 0)
    max_odd = max(num_gen, default=None)
    if max_odd is None:
        print("No odd number was entered")
    else:
        print(f"The largest odd number is: {max_odd}")

O empacotamento int(input("Enter a number: "))em uma função fornece melhor legibilidade:

def read_input() -> int:
    return int(input("Enter a number: "))

if __name__ == "__main__":
    num_gen = (o for _ in range(10) if (o := read_input()) % 2 != 0)
    max_odd = max(num_gen, default=None)
    if max_odd is None:
        print("No odd number was entered")
    else:
        print(f"The largest odd number is: {max_odd}")

Outra variante que lida com entradas de usuário inválidas é a seguinte:

def read_input() -> int:
    while True:
        try:
            return int(input("Enter a number: "))
        except ValueError:
            continue

if __name__ == "__main__":
    try:
        max_odd = max(o for _ in range(10) if (o := read_input()) % 2 != 0)
        print(f"The largest odd number is: {max_odd}")
    except ValueError:
        # Since read_input() no longer raises ValueError, the except
        # statement here only handles the cases where max() gets no inputs
        print("No odd number was entered")
3 AlexeyBurdin Aug 19 2020 at 12:56

Posso perguntar qual linguagem de programação você praticava antes do python?
Quero mencionar uma linha para isso:

max(l,key=lambda x:(x%2,x))

presumindo que você já tenha linserido de alguma forma, como

s='Enter a number: '
l=[int(input(s)) for i in range(10)]

Como funciona o código? Procura no máximo key(x)para xem le retorna tal x. A chave aqui é a função lambda que retorna tupla (1,x)para ímpar xe (0,x)par x. As tuplas são comparadas da esquerda para a direita, por exemplo, (1,x)>(0,y)para cada xe y. Portanto, estamos apenas dizendo "dê-me o máximo de l, assumindo que um número ímpar é sempre maior do que um número par".

Portanto, todo o programa será semelhante

s='Enter a number: '
l=[int(input(s)) for i in range(10)]
m=max(l,key=lambda x:(x%2,x))
if m%2:
    print('The largest odd number is: %d'%m)
else: #the greatest is even, therefore no odd numbers
    print('No odd number was entered')

Curto, agradável e fácil, como python.

Mas concordo que um bloco try-except em torno int(input())da resposta aceita é útil, junto com nenhum pré-armazenamento de toda a lista de valores ímpares.

Eu só queria demonstrar o paradigma da programação funcional em python, quando você apenas diz a python 'Eu quero que isso seja feito (por exemplo, um valor máximo)' e ele faz isso por você, você não precisa explicar como deveria fazer.

Obrigado pela leitura.

3 EmilioMBumachar Aug 19 2020 at 21:36

Tentarei aproveitar a última sugestão da resposta aceita.

while True:
    try:
        x = int(input("Enter a number: "))
        break
    except ValueError:
        continue

Eu definitivamente endosso essa sugestão, ela permite que seu programa trate entradas inválidas normalmente em vez de apenas travar.

No entanto, isso cria um problema de usabilidade. O usuário que acabou de digitar uma letra em um número provavelmente não percebeu. Eles pensarão que inseriram o número pretendido, continuarão com o próximo e ficarão confusos no final, quando acharem que inseriram todos os números, mas o computador ainda está pedindo o próximo.

Melhor dar feedback:

while True:
    try:
        x = int(input("Enter a number: "))
        break
    except ValueError:
        print("Invalid number will be ignored.")
        continue

... ou melhor ainda, imprima o número digitado de volta para eles:

while True:
    try:
        inputString = input("Enter a number: ")
        x = int(inputString)
        break
    except ValueError:
        print("Invalid number will be ignored: {}".format(inputString))
        continue

Também consideraria manter a lista completa de números válidos inseridos, não apenas os ímpares, e imprimi-los todos de volta para o usuário antes do resultado, para dar a eles uma última chance de detectar erros de digitação. Afinal, eles podem ter digitado incorretamente um número válido, mas não intencional. Observe que isso aumentaria o uso de memória e alguns considerariam um excesso de comunicação.

print("Numbers provided are: {}".format(all_valid_numbers_inputted))
if not odds:
    print("No odd number was entered")
else:
    print("The largest odd number is:", max(odds))

Se você fizer isso, a próxima etapa será livrar-se da variável "probabilidades" e calcular a maior ímpar diretamente da lista completa.

1 FMc Aug 25 2020 at 12:23

O ponto principal aqui: cada etapa do processo faz apenas uma coisa simples. Você cria programas dessa maneira - uma etapa incremental e bem definida de cada vez. Não misture tudo em uma confusão - por exemplo, um loop onde interagimos com um usuário enquanto também fazemos conversões e cálculos necessários mais tarde.

def as_int(s):
    try:
        return int(s)
    except Exception:
        return 0

N = 3
MSG = 'Enter number: '

replies = [input(MSG) for _ in range(N)]  # Interact.
nums = [as_int(r) for r in replies]       # Convert.
odds = [n for n in nums if n % 2]         # Compute.

if odds:                                  # Report.
    print(max(odds))