Problem with Python matrices

Asked

Viewed 1,384 times

0

Hi, I’d like some help. I have to generate, in Python, a matrix with a number l of rows and a number c of columns, and calculate the sum of the main and secondary diagonal elements. The sum is done correctly, but it saves each row of the matrix over the previous line, so when I print the matrix, it only repeats the last line several times. If anyone can help me, I would be very grateful. Follow the code:

# Programa para processar e imprimir uma matriz l x c
# Calcular o somatório dos elementos das diagonais principal e secundária
l = int(input("Insira o número de linhas: "))
c = int(input("Insira o número de colunas: "))
matriz = [[0] * c] * l
soma1 = int(0)
soma2 = int(0)
for i in range(0, l):
    for j in range(0, c):
        matriz[i][j] = int(input(f"Insira o elemento {j+1} da linha {i+1}: "))
    soma1 = soma1 + matriz[i][i]
    soma2 = soma2 + matriz[i][l - 1 - i]
print("\nElementos da matriz: ")
for i in range(0, l):
    print(matriz[i])
if l == c:
    print("\nSomatório dos elementos da diagonal principal =", soma1)
    print("Somatório dos elementos da diagonal secundária =", soma2)
else:
    print("A matriz não é quadrada, logo não possui diagonais.")

As you can see by the code, I’m very beginner in the language, so I would like you not to solve the problem with very complex commands, if possible, but if necessary I do my best to understand. From now on, thank you very much.

  • Related: https://answall.com/questions/183508

3 answers

0

The problem lies in that line:

matriz = [[0] * c] * l

We will divide it into two commands to facilitate the explanation:

linha = [0] * c
matriz = [linha] * l

When creating the internal list (called linha in the example) using [0] * c, the code is using the reference multiplication operator. A new list is created with a total of c references to the object 0. No other objects are created 0 but that’s no problem in this case because 0 is int and ints are immutable in python.

By taking this list and multiplying [linha] * l, the same happens, but they are created l references to the same list linha. Its variable matrix then becomes a list with multiple references, all pointing to the same list...

The problem is that lists are mutable. By modifying an element of the internal list:

matriz[i][j] = int(input(....))

All lines will be affected, because in fact there is only one single line, referenced multiple times!

One way to solve is to force the creation of multiple independent lists:

matriz = [[0 for x in c] for y in l]

0

Note: We can only operate diagonals of a matrix if it is SQUARE.

In other words, it only makes sense to speak in diagonals if the number of rows in the matrix is igual to the number of columns. Otherwise, it makes no sense to speak in diagonals.

When we have a matrix A(1 x 1), we say that matrix A is quadrada e de ordem "1" and when we have a matrix B(2 x 2), we say that matrix B is quadrada e de ordem "2" and so, successively.

So when we’re operating with square matrices, we just specify your ordem to immediately subtender the number of rows and columns which are therefore equal.

When the questioner says that he wishes to calculate the soma dos elementos da diagonal principal he is referring to trait of the matrix and when it says it wants to calculate the soma dos elementos da diagonal secundária he is referring to anti-trafficking of the matrix.

Both the traço like the anti-traço can only be calculated if the matrix is square.

To solve this question we can implement the following algorithm...

import numpy as np

# Capturando e tratando a ordem da matriz quadrada.
while True:
    try:
        m = int(input('Digite a ordem da matriz: '))
        if m < 1:
            print('\033[31mValor INVÁLIDO! Digite inteiros maiores que "0"!\033[m')
        else:
            break
    except ValueError:
        print('\033[31mValor INVÁLIDO! Digite apenas valores inteiros!\033[m')

# Montando a matriz quadrada de ordem "m".
matrizTemp = list()
for c in range(1, m + 1):
    linha = list()
    for i in range(1, m + 1):
        # Capturando e tratando os valores de cada elemento da matriz.
        while True:
            try:
                valor = int(input(f'Digite o {i}º elemento de {c}ª linha: '))
                break
            except ValueError:
                print('\033[31mValor INVÁLIDO! Digite apenas inteiros!\033[m')
        linha.append(valor)
    matrizTemp.append(linha)

# Organizando de forma espacial a matriz.
matriz = np.array(matrizTemp)
matriz_in = np.fliplr(matriz)

# Calculando o traço e o antitraço da matriz.
traco = np.trace(matriz)
antitraco = np.trace(matriz_in)

# Exibindo os resultados.
print(f'\033[32mA matriz gerada é:\n{matriz}')
print(f'A soma dos elementos da diagonal principal é: {traco}')
print(f'A soma dos elementos da diagonal secundária é: {antitraco}\033[m')

See here the functioning of the algorithm.

Note that when we run the algorithm we receive the message; Digite a ordem da matriz. Right now we must enter a number inteiro and maior que zero. from that moment we must enter each element of the matrix and then press enter.

After we have typed all the elements of the matrix the algorithm will mount and display the matrix, in addition to calculating its traço and anti-traço respectively.

See here the meaning of the term fliplr used in the code...

matriz_in = np.fliplr(matriz)

...also note here the applications of the term trace used in codes...

traco = np.trace(matriz)

and..

antitraco = np.trace(matriz_in)

Observing

Realize that the bigger the ordem of the square matrix, the largest will be the total de elementos to be inserted into the matrix.

0


Well, I don’t think what I’m going for is complex, I’m going to put a few comments in case you don’t understand.

# PEGUEI SEU CÓDIGO PARA FACILITAR VOU DEIXAR ELE MAIS EXTENSO MESMO QUE NÃO ESTEJA 
OTIMIZADO
# Programa para processar e imprimir uma matriz l x c
# Calcular o somatório dos elementos das diagonais principal e secundária
l = int(input("Insira o número de linhas: "))
c = int(input("Insira o número de colunas: "))
matriz = [] #vou apenas descomplicar colocando abaixo uma lista por linha

somaprincipal = 0 # meio desnecessário fazer o casting afinal, python não é uma linguagem fortemente tipada
somasecundaria = 0

for i in range(0, l):
    matriz.append([]) #adiciona uma lista sempre que percorre o loop, mas do seu jeito é mais rápido
    for j in range(0, c):
        matriz[i].append(int(input(f"Insira o elemento {j+1} da linha {i+1}: ")))
        if i == j: # só soma quando o número da linha é o mesmo número da coluna.
            somaprincipal += matriz[i][j] 

for i in range(-1,(-l-1), -1): # percorre a lista do último item ao primeiro
    for j in range(-1,(-c-1), -1): # o mesmo de cima
        if i == j:
            somasecundaria += matriz[i][j]


print("\nElementos da matriz: ")
for i in range(0, l):
    print(*matriz[i]) #printa a matriz sem mostrar os colchetes nem vírgulas
if l == c:
    print("\nSomatório dos elementos da diagonal principal =", somaprincipal)
    print("Somatório dos elementos da diagonal secundária =", somasecundaria)
else:
    print("A matriz não é quadrada, logo não possui diagonais.")

So it solves the problem, however the problem of your code is that lists are mutable, take a print every time you change/add a list item so you see that the way the code is, whenever you modify an element it will modify the rest and so on, so I went to add list by list, not to have this problem of them being "linked" because when you did this

matriz = [[0] * c] * l 

just made the address in the memory of the list go to each of the indices on the list, I hope you understood.

that link can help you see/understand that the lists were only copied to the address and no other were created.

  • if you cannot open the link correctly (I could not after sending) is here https://stackoverflow.com/questions/16408472/print-memory-address-of-python-variable

Browser other questions tagged

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