Lesson 9
Listas bidimensionais (arrays)
1. Listas aninhadas: processamento e impressão
No mundo real Freqüentemente, as tarefas precisam armazenar a tabela de dados retangular. [fale mais sobre isso!] Essas tabelas são chamadas matrizes ou matrizes bidimensionais. No Python, qualquer tabela pode ser representada como uma lista de listas (uma lista, onde cada elemento é, por sua vez, uma lista). Por exemplo, aqui está o programa que cria uma tabela numérica com duas linhas e três colunas e, em seguida, faz algumas manipulações com ela:a = [[1, 2, 3], [4, 5, 6]] print(a[0]) print(a[1]) b = a[0] print(b) print(a[0][2]) a[0][1] = 7 print(a) print(b) b[2] = 9 print(a[0]) print(b)
O primeiro elemento de a
aqui - a[0]
- é uma lista de números [1, 2, 3]
. O primeiro elemento desta nova lista é a[0][0] == 1
; Além disso, a[0][1] == 2
, a[0][2] == 3
, a[1][0] == 4
, a[1][1] == 5
, a[1][2] == 6
.
Para processar uma matriz bidimensional, você normalmente usa loops aninhados. O primeiro loop percorre o número da linha, o segundo loop percorre os elementos dentro de uma linha. Por exemplo, é assim que você exibe a lista numérica bidimensional na tela linha por linha, separando os números por espaços:
a = [[1, 2, 3, 4], [5, 6], [7, 8, 9]] for i in range(len(a)): for j in range(len(a[i])): print(a[i][j], end=' ') print()
Nós já tentamos explicar que uma variável for-loop no Python pode iterar não apenas sobre um range()
, mas geralmente sobre todos os elementos de qualquer sequência. Seqüências em Python são listas e strings (e alguns outros objetos que ainda não conhecemos). Veja como você pode imprimir uma matriz bidimensional, usando este recurso útil de loop for
:
a = [[1, 2, 3, 4], [5, 6], [7, 8, 9]] for row in a: for elem in row: print(elem, end=' ') print()
Naturalmente, para gerar uma única linha, você pode usar o método join()
:
for row in a: print(' '.join([str(elem) for elem in row]))
É assim que você pode usar dois loops aninhados para calcular a soma de todos os números da lista bidimensional:
a = [[1, 2, 3, 4], [5, 6], [7, 8, 9]] s = 0 for i in range(len(a)): for j in range(len(a[i])): s += a[i][j] print(s)
Ou o mesmo com a iteração por elementos, e não pelas variáveis i
e j
:
a = [[1, 2, 3, 4], [5, 6], [7, 8, 9]] s = 0 for row in a: for elem in row: s += elem print(s)
2. Listas aninhadas: criando
Suponha que dois números sejam dados: o número de linhas de n
e o número de colunas m
. Você deve criar uma lista de tamanho n
× m
, preenchida com, digamos, zeros.
A solução óbvia parece estar errada:
a = [[0] * m] * n
Isto pode ser facilmente visto se você definir o valor de a[0][0]
para 5
, e depois imprimir o valor de a[1][0]
- ele também será igual a 5. O motivo é [0] * m
retorna apenas uma referência a uma lista de m
zeros, mas não uma lista. A repetição subsequente desse elemento cria uma lista de n
itens que fazem referência à mesma lista (assim como a operação b = a
para listas não cria a nova lista), portanto, todas as linhas na lista resultante são realmente as mesmas corda.
Usando nosso visualizador, controle o id das listas. Se duas listas tiverem o mesmo número de identificação, na verdade é a mesma lista na memória.
n = 3 m = 4 a = [[0] * m] * n a[0][0] = 5 print(a[1][0])
Assim, uma lista bidimensional não pode ser criada simplesmente repetindo uma string. O que fazer?..
Uma maneira possível: você pode criar uma lista de n
elementos (digamos, de n
zeros) e então fazer de cada um dos elementos um link para outra lista unidimensional de m
elementos:
n = 3 m = 4 a = [0] * n for i in range(n): a[i] = [0] * m
Outra maneira (mas semelhante): criar uma lista vazia e, em seguida, append
um novo elemento n
vezes (este elemento deve ser uma lista de comprimento m
):
n = 3 m = 4 a = [] for i in range(n): a.append([0] * m)
Mas a maneira mais fácil é usar o gerador, criando uma lista de n
elementos, cada um dos quais é uma lista de m
zeros:
n = 3 m = 4 a = [[0] * m for i in range(n)]
Neste caso, cada elemento é criado independentemente dos outros. A lista [0] * m
é n
vezes consertada como a nova, e nenhuma cópia de referências ocorre.
3. Como você insere um array bidimensional?
Digamos que um programa receba uma matriz bidimensional de entrada na forma de n
linhas, cada uma contendo m
números separados por espaços. Como você força o programa a lê-lo? Um exemplo de como você pode fazer isso:
# a primeira linha de entrada é o número de linhas da matriz n = int(input()) a = [] for i in range(n): a.append([int(j) for j in input().split()])
Ou, sem usar chamadas aninhadas sofisticadas:
# a primeira linha de entrada é o número de linhas da matriz n = int(input()) a = [] for i in range(n): row = input().split() for i in range(len(row)): row[i] = int(row[i]) a.append(row)
Você pode fazer o mesmo com geradores:
# a primeira linha de entrada é o número de linhas da matriz n = int(input()) a = [[int(j) for j in input().split()] for i in range(n)]
4. Processando uma matriz bidimensional: um exemplo
Suponha que você receba uma matriz quadrada (uma matriz de n
linhas e n
colunas). E suponha que você tenha que definir elementos da diagonal principal igual a 1 (isto é, esses elementos a[i][j]
para os quais i==j
), definir elementos acima da diagonal igual a 0 e definir elementos abaixo dessa diagonal igual a 2. Ou seja, você precisa produzir tal matriz (exemplo para n==4
):
1 0 0 0 2 1 0 0 2 2 1 0 2 2 2 1(Nesse caso, você pode fazer isso manualmente definindo
a[0][0] = 1
, a[0][1] = 0
e assim por diante, mas você não fará isso manualmente para matrizes de 100 linhas e 100 colunas , que são frequentemente o caso. Estamos ansiosos para lhe mostrar várias maneiras de resolver este problema. Primeiro, observe que os elementos que estão acima da diagonal principal - são elementos a[i][j]
para os quais i<j
, e os elementos abaixo da diagonal principal i>j
. Assim, podemos comparar os valores i
e j
, que determina o valor de a[i][j]
. Nós obtemos o seguinte algoritmo:
n = 4 a = [[0] * n for i in range(n)] for i in range(n): for j in range(n): if i < j: a[i][j] = 0 elif i > j: a[i][j] = 2 else: a[i][j] = 1 for row in a: print(' '.join([str(elem) for elem in row]))
Este algoritmo é lento: ele utiliza duas voltas e para cada par (i,j)
executa um ou dois if
instruções. Se complicarmos o algoritmo, poderemos fazê-lo sem uma instrução condicional.
Primeiro, preencha a diagonal principal, para a qual precisaremos de um loop:
for i in range(n): a[i][i] = 1
Em seguida, preencha com zeros todos os elementos acima da diagonal principal. Para fazer isso, para cada linha com o número i
você precisa atribuir um valor a a[i][j]
para j
= i+1
, ..., n-1
. Para fazer isso, você precisa de loops aninhados:
for i in range(n): for j in range(i + 1, n): a[i][j] = 0
Por analogia, para j
= 0
, ..., i-1
defina os elementos a[i][j]
igual a 2
:
for i in range(n): for j in range(0, i): a[i][j] = 2
Você pode combinar todo esse código e receber outra solução:
n = 4 a = [[0] * n for i in range(n)] for i in range(n): for j in range(0, i): a[i][j] = 2 a[i][i] = 1 for j in range(i + 1, n): a[i][j] = 0 for row in a: print(' '.join([str(elem) for elem in row]))
Aqui está outra solução, que repete listas para construir as próximas linhas da lista. A i
ésima linha da lista consiste em i
números 2
, seguidos por um inteiro 1
, seguido por ni-1
zeros:
n = 4 a = [0] * n for i in range(n): a[i] = [2] * i + [1] + [0] * (n - i - 1) for row in a: print(' '.join([str(elem) for elem in row]))
Como de costume, você pode substituir o loop com o gerador:
n = 4 a = [0] * n a = [[2] * i + [1] + [0] * (n - i - 1) for i in range(n)] for row in a: print(' '.join([str(elem) for elem in row]))
5. Matrizes bidimensionais: geradores aninhados
Você pode usar geradores aninhados para criar matrizes bidimensionais, colocando o gerador da lista que é uma string dentro do gerador de todas as strings. Recorde-se que é possível criar uma lista de n
linhas e m
colunas, utilizando o gerador (que cria uma lista de n
elementos, em que cada elemento é uma lista de m
zeros):
[[0] * m for i in range(n)]
Mas a lista interna também pode ser criada usando, por exemplo, esse gerador: [0 for j in range(m)]
. Aninhando um gerador em outro, obtemos
[[0 for j in range(m)] for i in range(n)]
Como isso está relacionado ao nosso problema? A coisa é, se o número 0 for substituído por alguma expressão que depende de i
(o número da linha) j
(o número da coluna), você obtém a matriz preenchida de acordo com alguma fórmula.
Por exemplo, suponha que você precise inicializar o seguinte array (por conveniência, espaços extras são adicionados entre os itens):
0 0 0 0 0 0 0 1 2 3 4 5 0 2 4 6 8 10 0 3 6 9 12 15 0 4 8 12 16 20
Nesta matriz existem n = 5
linhas, m = 6
colunas, e o elemento com índice de linha i
e índice de coluna j
é calculado pela fórmula a[i][j] = i * j
.
Como sempre, você poderia usar o gerador para criar uma matriz:
[[i * j for j in range(m)] for i in range(n)]