What is wrong with python below? Any suggestions for another solution?

Asked

Viewed 100 times

-2

Problem: Having a 5 5 matrix filled with random (real) values between 0 and 99, show which is the second highest value existing in the matrix.

Can’t use numpy or similar.

My solution:

n=2
def constroi_matriz(n):
    import random
    matriz =[[]]
    linha =[]
    for i in range(n):
        for j in range(n):
            num = random.randint(0,99)
            linha.append(num)
        matriz.append(linha)
        linha =[]
    matriz.pop(0)#excluir a posicao que contem []
    return matriz


def segundo_maior(matriz):
 maior = max(max(matriz))
 for i in range(len(matriz)):
     for j in range(len(matriz)):
         if matriz[i][j] == maior:
             matriz[i].remove(maior)
             print(matriz)




 return max(max(matriz))

matriz = constroi_matriz(2)
print(f"A matriz é {matriz}")
print(f"O segundo maior é: {segundo_maior(matriz)}")

I don’t know why I sometimes get error from "builtins.Indexerror: list index out of range"

  • 2

    Have you done the table test of your code? There are several strange things in it: 1) no need to start matriz with an empty list and will then remove it; 2) max(max(matriz)) will not return the highest matrix value; 3) you define the function segundo_maior and never calls it; 4) in the function segundo_maior you delete matrix elements, which doesn’t make much sense;

  • Woss: yes. and I couldn’t figure out what was wrong...

  • Can you show us the results of your table test?

  • @Woss: I did trying to run on paper and did not find the error in my logic!

  • @Woss: I had forgotten to put the function calls. I edited the question!

  • 1

    I recommend starting studying as Find the largest and smallest element of a matrix; for the second largest, simply replicate the same lobe of the largest by adding the condition that the second largest cannot be greater than the largest. On how to create an array, see How to create a python array

Show 1 more comment

2 answers

2

TL;DR

Knowing a little the modules that Python provides and some language functionality you can do it in a simpler way:

from random import randint
from itertools import chain


def constroi_matriz(m, n, min_num=0, max_num=99):
    return [ 
        [randint(min_num, max_num) for _ in range(m)]
        for _ in range(n)
    ]


def segundo_maior(matriz):
    return sorted(chain.from_iterable(matriz))[-2]


matriz = constroi_matriz(5, 5)

print(matriz)
print(segundo_maior(matriz))

See rotating on Repl.it


Explanation

In function constroi_matriz used list comprehensions to create the matrix, where:

matriz = [ 
    [randint(min_num, max_num) for _ in range(m)]
    for _ in range(n)
]

Would be equivalent to:

matriz = []
for i in range(m):
    matriz.append([])
    for j in range(n):
        matriz[i].append(j)

PS: In the documentation of list comprehensions you will see that they can repeat themselves N for to create as many matrix dimensions as you want.

Already in office segundo_maior I follow a simpler rule:

  1. Turn the matrix into a list using itertools.chain.from_iterable. Ex.:

    from itertools import chain
    
    matriz = [[10, 20, 30], [5, 50, 500]]
    lista = chain.from_iterable(matriz)
    print(lista)
    # [10, 20, 30, 5, 50, 500]
    
  2. I sort this list using the function sorted. Ex.:

    lista = [10, 20, 30, 5, 50, 500]
    ordenada = sorted(lista)
    print(ordenada)
    # [5, 10, 20, 30, 50, 500]
    

    OBS.: sorted returns a new list with the sorted data, keeping the original list. If you want to overwrite the original list you should use list.sort(). Related questions: ""Sort" method returning only "None", what is the reason?" and "Method Reverse returns None".

  3. I take the penultimate item on the orderly list, that is, the second largest. Ex.:

    ordenada = [5, 10, 20, 30, 50, 500]
    print(ordenada[-2])
    # 50
    

1

your problem this on this line, it may change the length of the list but as this inside a codition is not always it will make this change that causes the problem.

matriz[i].remove(maior)  

I’ve made some changes, as a suggestion

n=2
def constroi_matriz(n):
    import random
    matriz =[] 
    for i in range(n):
        linha =[] 
        for j in range(n):
            num = random.randint(0,99)
            linha.append(num)
        matriz.append(linha)
    return matriz


def segundo_maior(matriz):
    maior = []
    for i in matriz:
        maior.extend(i)
    maior.sort()
    return maior[-2]

matriz = constroi_matriz(n)
print('A matriz é', *matriz, sep='\n')
print(f"O segundo maior é: {segundo_maior(matriz)}") 

in that second code would be a more lazy approach

from random import randint
from itertools import chain

n=2

def constroi_matriz(n):
    matriz =[[randint(0, 99) for x in range(n)]
            for y in range(n)]
    return matriz


def segundo_maior(matriz):
    lista = [x for x in chain(*matriz)]
    lista = sorted(set(lista))

    if len(lista) > 1:
        return lista[-2]
    return lista[0]

matriz = constroi_matriz(n)
print('A matriz é', *matriz, sep='\n')
print(f"O segundo maior é: {segundo_maior(matriz)}")  insira o código aqui

in this case I do some conversions, of list for set which removes all equality, and back to list to organize and take the position

  • Some simpler way to do than the one I tried?

  • I noticed that the failed code qdo receives matrix with repeated values: The matrix is [1, 1] [2, 2] The second major is: 2

Browser other questions tagged

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