How to print more than a maximum number of a list

Asked

Viewed 140 times

0

Guys the exercise of my college is as follows: Write a program that receives the names of 5 students and put in a list and their respective notes in another list.

The exercise asks to print the highest student’s grade (What I’ve already managed to do), but I’m not able to print the name of more than one student (In case of top grade draw), so far my code is like this:

aluno = []
nota = []


while len(aluno) < 5:
    aluno.append(input('Digite o nome do aluno'))
    nota.append(int(input('Digite a média final do aluno')))

print(f'O aluno com maior nota foi o {aluno[nota.index(max(nota,key=int))]}')

4 answers

4

While the other answers work, there’s one detail I’d like to comment on.

They are calling max several times, no need. To better understand, we will modify only a little the program:

def maior(notas):
    print('procurando maior nota')
    return max(notas)

aluno = ["alice", "bob", "carol", "dave", "eve"]
notas = [10, 7, 9, 10, 10]
maiores_notas = [aluno[i] for i in range(len(aluno)) if notas[i] == maior(notas)]

That is, I created another function that calls max but also prints a message. The output is:

procurando maior nota
procurando maior nota
procurando maior nota
procurando maior nota
procurando maior nota

The function was called 5 times (one for each note). But this is redundant and unnecessary, as the list of notes will no longer be modified and therefore I only need to search once. The problem here is that max goes through all the elements of the list to find the largest, and when you go through the same list several times without need, you are creating a variation of the call Shlemiel the Painter’s Algorithm (which is a jocose synonym for a "dumb algorithm").


Anyway, a better solution is to get the biggest just once, and then check the students who have this grade.

And as already suggested in another answer, you can use zip to scroll through both lists at the same time:

alunos = [] 
notas = []
for _ in range(5): 
    alunos.append(input('Digite o nome do aluno: ')) 
    notas.append(int(input('Digite a média final do aluno: ')))

maior_nota = max(notas) # agora eu só chamo max uma única vez
maiores_notas = [ aluno for aluno, nota in zip(alunos, notas) if nota == maior_nota ]

I used a range to repeat the reading of the data 5 times (and I used the variable _ in the for, which is a Python convention to indicate that the variable is not used in loop - I just want to repeat something 5 times, but I won’t use the variable in the iteration).

I also renamed the lists to alunos and notas (both plural), since they will hold several students and grades respectively. It may seem like a minor detail, but give names better help when programming.


Of course, for small lists the difference will be insignificant, and if it’s just an exercise, maybe it’s just micro-optimization. But run several times to larger lists and you will begin to make a considerable difference. Remember that for few data, everything is fast.

Doing a test with the module timeit, we can see the difference:

from timeit import timeit
from random import choices

chamar_uma_vez = "maior_nota = max(notas)\nmaiores_notas = [ aluno for aluno, nota in zip(alunos, notas) if nota == maior_nota ]"
chamar_varias_vezes = "maiores_notas = [ aluno for aluno, nota in zip(alunos, notas) if nota == max(notas) ]"

qtd = 1000
alunos = list(range(qtd)) # cria uma lista com 1000 elementos
notas = choices(range(11), k=qtd) # cria uma lista com 1000 notas aleatórias entre 0 e 10

execucoes = 1000 # executar mil vezes cada um
# imprime o tempo em segundos para cada um dos algoritmos
print(timeit(stmt=chamar_uma_vez, number=execucoes, globals=globals()))
print(timeit(stmt=chamar_varias_vezes, number=execucoes, globals=globals()))

First, it is worth remembering that times can vary from one machine to another, because it depends on several factors, such as the hardware, if there were other things running on the machine, etc.

But anyway, creating lists with 1000 students and 1000 grades, and running 1000 times each search, on my machine I got 0.07 seconds in the first solution (calling max only once) and 21 seconds in the second solution (calling max several times). That is, almost 300 times slower. I ran several times and the results did not vary much beyond that.

In the Repl.it times were different (around 0.3 to 0.4 seconds for the first solution and around 80 seconds for the second), but still we see that call max several times was about 200 times slower.

Using lists with 10 notes, the difference is no longer so great (0.001 versus 0.005), but as I have already said, for small lists the difference is imperceptible. But that’s where the danger lies: you see that it "works" and you will only notice that there is a problem up front. Despite being "only an exercise", it is important to pay attention to these details from now on, so as not to think that any code that "works" is necessarily a good code.

1

A way to do that is the following:

aluno = ["alice", "bob", "carol", "dave", "eve"]
notas = [10, 7, 9, 10, 10]

maiores_notas = [aluno[i] for i in range(len(aluno)) if notas[i] == max(notas)]

That way, you iterate on the list aluno filtering only students who have the highest grade in the list notas.

0

From what I understand you want to implement an algorithm that is able to capture the name of 5 students, storing them within a list and capturing the notes of these 5 students, storing them within another list. Then the code is able to identify the greater grade and tell which students got the highest grade.

Well, the logic of this code will be as follows::

  1. Capture and store the name of the 5 students in a list;
  2. Capture and store the grades of these 5 students in another list;
  3. Calculate the highest grade;
  4. Identify the student(s) (s) who obtained (ram) the highest grade.

Observing

How students' grades can come in shape...

7, 7.5, 8, 9.5

..I thought I’d use the float and not the kind int.

One of the correct ways to implement this code is:

nomes = list()
notas = list()
for i in range(1, 6):
    nomes.append(input(f'Digite o nome da {i}ª pessoa: ').capitalize())
    notas.append(float(input(f'Digite a nota de {nomes[i - 1]}: ')))

maior_nota = max(notas)

print(f'A maior nota foi {maior_nota}, sendo a mesma obtida pelo(s) aluno(s):')
for j, k in zip(nomes, notas):
    if k == maior_nota:
        print(j)

Note that the first block for assembles the two lists - names and notes. After that the highest note is calculated. Then the second block for - with the help of the zip() function - traverse the two lists simultaneously, checking the occurrences of the highest note and, for each occurrence of the highest note, the name of the person who obtained it is printed.

At the end of the execution of this code, we will have the name of each person who got the highest grade.

0

You can use list comprehension and use the zip function:

aluno = [] 
nota = []

while len(aluno) < 5: 
    aluno.append(input('Digite o nome do aluno: ')) 
    nota.append(int(input('Digite a média final do aluno: ')))

In this section we check the highest grades:

maiores_notas = [a for a, n in zip(aluno, nota) if n == max(nota) ]

Printing:

print(f'\nO(s) aluno(s) com maior(es) nota(s): {", ".join(maiores_notas)}')

Browser other questions tagged

You are not signed in. Login or sign up in order to post.