Como definir uma matriz bidimensional em Python

724

Eu quero definir uma matriz bidimensional sem um comprimento inicializado como este:

Matrix = [][]

mas não funciona...

Eu tentei o código abaixo, mas também está errado:

Matrix = [5][5]

Erro:

Traceback ...

IndexError: list index out of range

Qual é o meu erro?

Masoud Abasian
fonte
14
Não se define matrizes ou qualquer outra coisa. Você pode, no entanto, criar seqüências multidimensionais, como mostram as respostas aqui. Lembre-se de que as variáveis python são sem tipo, mas os valores são fortemente digitados.
SingleNegationElimination
1
Estou confuso. Vindo de outros idiomas: é uma diferença entre um 1D-Array contendo 1D-Array e um 2D-Array. E o AFAIK não tem como ter um array multidimensional (ou lista) em python. Deve ser dito aqui ...
Dirk Reichel
1
Veja também as Perguntas freqüentes do Python3 sobre Como criar uma lista multidimensional?
Kevin W Matthews

Respostas:

1009

Tecnicamente, você está tentando indexar uma matriz não inicializada. Você precisa primeiro inicializar a lista externa com listas antes de adicionar itens; Python chama isso de "compreensão da lista".

# Creates a list containing 5 lists, each of 8 items, all set to 0
w, h = 8, 5;
Matrix = [[0 for x in range(w)] for y in range(h)] 

Agora você pode adicionar itens à lista:

Matrix[0][0] = 1
Matrix[6][0] = 3 # error! range... 
Matrix[0][6] = 3 # valid

Observe que a matriz é o endereço "y" principal, ou seja, o "índice y" vem antes do "índice x".

print Matrix[0][0] # prints 1
x, y = 0, 6 
print Matrix[x][y] # prints 3; be careful with indexing! 

Embora você possa nomeá-los como quiser, analiso desta maneira para evitar confusão que possa surgir com a indexação, se você usar "x" para as listas interna e externa e desejar uma matriz não quadrada.

Manny D
fonte
219
[[0 para x no intervalo (número_de_cols)] para x no intervalo (número de linhas)]
songhir 27/11
3
Edição ímpar por ademar111190. No Python 3, não há xrange, mas se você deve usar o Python 2, xrange é a função correta a ser usada, se você não deseja criar objetos desnecessariamente.
Dave
4
@ Dave Se você não precisa dele Zero-cheia, pode usar rangepara criar as listas internas diretamente:[range(5) for x in range(5)]
alanjds
2
@alanjds - isso é verdade, mas você ainda cria muitas referências de objetos desnecessárias no Python 2 para a iteração externa (tente isso com uma faixa MUITO grande). Além disso, a inicialização para algum valor é quase sempre o que você deseja - e isso geralmente é 0. O intervalo gera uma coleção iterável - xrange retorna um gerador. Meu argumento foi que ademar "corrigiu" algo que na verdade era mais geralmente correto e eficiente do que sua correção.
Dave
10
@ 6packkid a [0] * wpeça é boa, mas [[0] * w] * h]produzirá um comportamento inesperado. Tente mat = [[0] * 3] * 3; mat[0][1] = 10; print(mat == [[0, 10, 0], [0, 10, 0], [0, 10, 0]])e mat = [[0] * 3 for i in range(3)]; mat[0][1] = 10; print(mat == [[0, 10, 0], [0, 0, 0], [0, 0, 0]]).
Senderle
407

Se você realmente quer uma matriz, pode ser melhor usá-lo numpy. As operações de matriz na numpymaioria das vezes usam um tipo de matriz com duas dimensões. Existem muitas maneiras de criar uma nova matriz; uma das mais úteis é a zerosfunção, que pega um parâmetro de forma e retorna uma matriz da forma especificada, com os valores inicializados em zero:

>>> import numpy
>>> numpy.zeros((5, 5))
array([[ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.]])

Aqui estão algumas outras maneiras de criar matrizes e matrizes 2-d (com a saída removida para compactar):

numpy.arange(25).reshape((5, 5))         # create a 1-d range and reshape
numpy.array(range(25)).reshape((5, 5))   # pass a Python range and reshape
numpy.array([5] * 25).reshape((5, 5))    # pass a Python list and reshape
numpy.empty((5, 5))                      # allocate, but don't initialize
numpy.ones((5, 5))                       # initialize with ones

numpytambém fornece um matrixtipo, mas não é mais recomendado para nenhum uso e pode ser removido numpyno futuro.

remetente
fonte
79
Sempre que você quiser matrizes, deseja usar numpy. Esta resposta deve ser a primeira.
Pat B
2
O fato de a pergunta usar a palavra em inglês "matriz" não significa que eles devam usar np.matrixpara representá-la. A maneira correta de representar uma matriz em numpy é com um array.
User2357112 suporta Monica
@ user2357112, E como você pode ver, a maioria dos exemplos listados acima gera arrays em vez de matrizes. Embora nem sempre seja incentivado, existem razões legítimas para o uso de matrixquestões de contexto.
Senderle
1
@ remetente, você pode expandir as razões para usar matrix? Desde que o @operador foi introduzido, parece haver um motivo a menos desde que este post foi escrito.
jpp
1
@jpp, como o post disse anteriormente, as pessoas provenientes do matlab podem achar útil. Mas os numpydocumentos agora indicam que a classe pode ser preterida e removida no futuro, então tirei isso da resposta.
senderle
337

Aqui está uma notação mais curta para inicializar uma lista de listas:

matrix = [[0]*5 for i in range(5)]

Infelizmente, encurtar isso para algo como 5*[5*[0]]realmente não funciona, porque você acaba com 5 cópias da mesma lista; portanto, quando você modifica uma delas, todas elas mudam, por exemplo:

>>> matrix = 5*[5*[0]]
>>> matrix
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
>>> matrix[4][4] = 2
>>> matrix
[[0, 0, 0, 0, 2], [0, 0, 0, 0, 2], [0, 0, 0, 0, 2], [0, 0, 0, 0, 2], [0, 0, 0, 0, 2]]
Andrew Clark
fonte
4
Você poderia explicar a lógica por trás da falha de "redução"? Por que o python gera cópias da mesma lista nesse caso e uma matriz de células diferentes no caso de [0]*5?
Mike622867
12
Os comentários acima não são exatamente verdadeiros: [0] * 5 ainda cria uma sequência com 5 vezes uma referência ao mesmo objeto que representa o número 0. Mas você nunca notará isso porque 0 é imutável (eu diria que 0 se comporta como um valor - ou você pode pensar nisso como um tipo de dados primitivo - porque é imutável para que você nunca ter problemas com referências ao mesmo objeto em vez de ter cópias).
dreua
4
mais pítônico: [[0]*5 for _ in range(5)]com um contador de loop anônimo que você não está usando
Jean-François Fabre
É bom que você aponte o problema da cópia superficial no segundo exemplo.
whatacold
graças @dreua, fiquei realmente confuso sobre como [0]*5funciona muito bem. Agora entendo por [{0}]*8que seria uma má ideia também.
kuku
110

Se você deseja criar uma matriz vazia, a sintaxe correta é

matrix = [[]]

E se você deseja gerar uma matriz de tamanho 5 preenchida com 0,

matrix = [[0 for i in xrange(5)] for i in xrange(5)]
Mripard
fonte
@KorayTugay Porque a matriz é representada usando as listas Python (as linhas) aninhadas dentro de outra lista (as colunas).
elegível
2
Para a função gama uso-3 Python em vez xrange func
Rakesh Chaudhari
76

Se tudo o que você deseja é um contêiner bidimensional para conter alguns elementos, use um dicionário conveniente:

Matrix = {}

Então você pode fazer:

Matrix[1,2] = 15
print Matrix[1,2]

Isso funciona porque 1,2é uma tupla e você está usando-a como uma chave para indexar o dicionário. O resultado é semelhante a uma matriz esparsa muda.

Conforme indicado por osa e Josap Valls, você também pode usar Matrix = collections.defaultdict(lambda:0)para que os elementos ausentes tenham um valor padrão de 0.

Vatsal aponta ainda que esse método provavelmente não é muito eficiente para matrizes grandes e deve ser usado apenas em partes do código que não são críticas para o desempenho.

enobayram
fonte
2
Então você também pode fazer import collections; Matrix = collections.defaultdict(float), substituir zeros por elementos não inicializados.
Osa
2
O acesso a um ditado para tupla (1,2) como chave tem uma complexidade de pior caso de O (n). Como internamente, hash as tuplas. Enquanto o uso de uma matriz 2D daria a O (1) complexidade de tempo para acessar o acesso ao índice [1,2]. Portanto, usar dict para isso não deve ser uma boa escolha.
Vatsal
O @Vatsal wiki.python.org/moin/TimeComplexity diz que o caso médio é O (1), mas você está certo sobre o pior caso. De qualquer forma, a menos que você esteja falando de MUITOS ITENS, não se importaria com essa diferença. Por uma questão de fato, eu estaria mais preocupado com a memória do que com o tempo de acesso.
Enobayram #
Também tentamos sempre evitar o uso de dictos até que a complexidade geral do algoritmo seja igual ou superior a O (n ^ 2). Como 'n' vezes O (n) acessos daria uma complexidade O (n ^ 2).
Vatsal
@enobayram, Desculpe, mas eu não concordo. A análise assintótica sempre fornecerá O (n ^ 2), se o pior caso de acesso a O (n) for feito 'n' vezes. Onde a análise amortizada pode dar um limite menor. E há uma enorme diferença entre caso amortizado e média ... por favor consulte antes de fazer quaisquer suposições e comentários vagos
Vatsal
42

No Python, você criará uma lista de listas. Você não precisa declarar as dimensões antes do tempo, mas pode. Por exemplo:

matrix = []
matrix.append([])
matrix.append([])
matrix[0].append(2)
matrix[1].append(3)

Agora matriz [0] [0] == 2 e matriz [1] [0] == 3. Você também pode usar a sintaxe de compreensão da lista. Este exemplo usa duas vezes para criar uma "lista bidimensional":

from itertools import count, takewhile
matrix = [[i for i in takewhile(lambda j: j < (k+1) * 10, count(k*10))] for k in range(10)]
amora
fonte
6
extendtambém seria útil no primeiro caso: Se você começar com m = [[]], poderá adicionar à lista interna (estender uma linha) com m[0].extend([1,2])e adicionar à lista externa (acrescentar uma nova linha) com m.append([3,4]), essas operações o deixarão com [[1, 2], [3, 4]].
askewchan
22

A resposta aceita é boa e correta, mas demorei um pouco para entender que eu também poderia usá-la para criar uma matriz completamente vazia.

l =  [[] for _ in range(3)]

resulta em

[[], [], []]
Fabian
fonte
22

Você deve fazer uma lista de listas e a melhor maneira é usar as compreensões aninhadas:

>>> matrix = [[0 for i in range(5)] for j in range(5)]
>>> pprint.pprint(matrix)
[[0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0]]

Nas suas [5][5] exemplo, você está criando uma lista com um número inteiro "5" dentro e tenta acessar seu quinto item, e isso naturalmente gera um IndexError porque não há um quinto item:

>>> l = [5]
>>> l[5]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range
utdemir
fonte
Na verdade, a sequência para row_index ('i') e column_index ('j') é a seguinte: '>>> matrix = [[0 para column_index no intervalo (5)] para row_index no intervalo (5)]'
Aniruddha Kalburgi
22
rows = int(input())
cols = int(input())

matrix = []
for i in range(rows):
  row = []
  for j in range(cols):
    row.append(0)
  matrix.append(row)

print(matrix)

Por que um código tão longo, que também em Python você também pergunta?

Muito tempo atrás, quando eu não estava confortável com o Python, vi as respostas de linha única para escrever a matriz 2D e disse a mim mesma que não usaria a matriz 2-D no Python novamente. (Essas linhas únicas eram bastante assustadoras e não me deram nenhuma informação sobre o que o Python estava fazendo. Observe também que não conheço essas taquigrafia).

De qualquer forma, aqui está o código para um iniciante que tem experiência em C, CPP e Java

Nota para amantes e especialistas em Python: Por favor, não vote abaixo apenas porque escrevi um código detalhado.

erro desconhecido
fonte
13

Uma reescrita para facilitar a leitura:

# 2D array/ matrix

# 5 rows, 5 cols
rows_count = 5
cols_count = 5

# create
#     creation looks reverse
#     create an array of "cols_count" cols, for each of the "rows_count" rows
#        all elements are initialized to 0
two_d_array = [[0 for j in range(cols_count)] for i in range(rows_count)]

# index is from 0 to 4
#     for both rows & cols
#     since 5 rows, 5 cols

# use
two_d_array[0][0] = 1
print two_d_array[0][0]  # prints 1   # 1st row, 1st col (top-left element of matrix)

two_d_array[1][0] = 2
print two_d_array[1][0]  # prints 2   # 2nd row, 1st col

two_d_array[1][4] = 3
print two_d_array[1][4]  # prints 3   # 2nd row, last col

two_d_array[4][4] = 4
print two_d_array[4][4]  # prints 4   # last row, last col (right, bottom element of matrix)
Manohar Reddy Poreddy
fonte
13

Usar:

matrix = [[0]*5 for i in range(5)]

O * 5 para a primeira dimensão funciona porque nesse nível os dados são imutáveis.

innov8
fonte
5
Eu provavelmente escreveria isso comomatrix = [[0]*cols for _ in range(rows)]
Shital Shah 20/02/19
12

Para declarar uma matriz de zeros (uns):

numpy.zeros((x, y))

por exemplo

>>> numpy.zeros((3, 5))
    array([[ 0.,  0.,  0.,  0.,  0.],
   [ 0.,  0.,  0.,  0.,  0.],
   [ 0.,  0.,  0.,  0.,  0.]])

ou numpy.ones ((x, y)), por exemplo

>>> np.ones((3, 5))
array([[ 1.,  1.,  1.,  1.,  1.],
   [ 1.,  1.,  1.,  1.,  1.],
   [ 1.,  1.,  1.,  1.,  1.]])

Até três dimensões são possíveis. ( http://www.astro.ufl.edu/~warner/prog/python.html, consulte -> Matrizes multidimensionais)

Khaz
fonte
12

É assim que costumo criar matrizes 2D em python.

col = 3
row = 4
array = [[0] * col for _ in range(row)]

Acho essa sintaxe fácil de lembrar em comparação com o uso de dois para loops em uma compreensão de lista.

Michael
fonte
11

Estou no meu primeiro script Python e fiquei um pouco confuso com o exemplo de matriz quadrada, então espero que o exemplo abaixo ajude você a economizar algum tempo:

 # Creates a 2 x 5 matrix
 Matrix = [[0 for y in xrange(5)] for x in xrange(2)]

de modo a

Matrix[1][4] = 2 # Valid
Matrix[4][1] = 3 # IndexError: list index out of range
user110954
fonte
10

Usando o NumPy, você pode inicializar a matriz vazia assim:

import numpy as np
mm = np.matrix([])

E depois acrescente dados como este:

mm = np.append(mm, [[1,2]], axis=1)
Namrata Tolani
fonte
quais seriam os prós e os contras do uso de numpy em vez de "compreensão da lista"?
Revolucion para Monica
7

Eu li em arquivos separados por vírgula assim:

data=[]
for l in infile:
    l = split(',')
    data.append(l)

A lista "dados" é então uma lista de listas com dados de índice [linha] [col]

wsanders
fonte
7

Se você quiser pensar nisso como uma matriz 2D, em vez de ser forçado a pensar no termo de uma lista de listas (muito mais natural na minha opinião), faça o seguinte:

import numpy
Nx=3; Ny=4
my2Dlist= numpy.zeros((Nx,Ny)).tolist()

O resultado é uma lista (não uma matriz NumPy) e você pode sobrescrever as posições individuais com números, cadeias de caracteres, o que for.

alessadnro
fonte
são numpy.matrixequivalentes a numpy.zerossem zeros sem estar na lista?
Revolucion para Monica
6

É para isso que serve o dicionário !

matrix = {}

Você pode definir chaves e valores de duas maneiras:

matrix[0,0] = value

ou

matrix = { (0,0)  : value }

Resultado:

   [ value,  value,  value,  value,  value],
   [ value,  value,  value,  value,  value],
   ...
Mohammad Mahdi KouchakYazdi
fonte
6

Usar:

import copy

def ndlist(*args, init=0):
    dp = init
    for x in reversed(args):
        dp = [copy.deepcopy(dp) for _ in range(x)]
    return dp

l = ndlist(1,2,3,4) # 4 dimensional list initialized with 0's
l[0][1][2][3] = 1

Eu acho que NumPy é o caminho a percorrer. O acima é genérico se você não quiser usar o NumPy.

pterodragão
fonte
Eu gosto dessa tentativa de fazer algo simples com o Python de baunilha sem precisar usar o numpy.
Rick Henderson
4

usando a lista:

matrix_in_python  = [['Roy',80,75,85,90,95],['John',75,80,75,85,100],['Dave',80,80,80,90,95]]

usando dict: você também pode armazenar essas informações na tabela de hash para pesquisas rápidas como

matrix = { '1':[0,0] , '2':[0,1],'3':[0,2],'4' : [1,0],'5':[1,1],'6':[1,2],'7':[2,0],'8':[2,1],'9':[2,2]};

matriz ['1'] resultará em tempo O (1)

* nb : você precisa lidar com uma colisão na tabela de hash

Saurabh Chandra Patel
fonte
4

Se você não tiver informações de tamanho antes do início, crie duas listas unidimensionais.

list 1: To store rows
list 2: Actual two-dimensional matrix

Armazene a linha inteira na 1ª lista. Quando terminar, anexe a lista 1 na lista 2:

from random import randint

coordinates=[]
temp=[]
points=int(raw_input("Enter No Of Coordinates >"))
for i in range(0,points):
    randomx=randint(0,1000)
    randomy=randint(0,1000)
    temp=[]
    temp.append(randomx)
    temp.append(randomy)
    coordinates.append(temp)

print coordinates

Resultado:

Enter No Of Coordinates >4
[[522, 96], [378, 276], [349, 741], [238, 439]]
Nagendra Nigade
fonte
3
# Creates a list containing 5 lists initialized to 0
Matrix = [[0]*5]*5

Tenha cuidado com esta expressão curta, veja a explicação completa na resposta de @ FJ

和風 信使
fonte
19
Tenha cuidado dessa maneira, porque Matrix[0], Matrix[1], ..., Matrix[4]todos apontam para a mesma matriz; portanto Matrix[0][0] = 3, você esperaria Matrix[0][0] == Matrix[1][0] == ... == Matrix[4][0] == 3.
gongzhitaao
1
Obrigado gongzhitaao pelo seu comentário. Se eu tivesse lido antes, teria me poupado pelo menos meia hora. Ter uma matriz onde cada linha aponta para o mesmo lugar na memória não parece ser muito útil, e se você não estiver ciente do que está fazendo até é perigoso! Tenho certeza de que NÃO é isso que Masoud Abasian, que fez a pergunta, quer fazer.
Adrian
7
Você deve remover esta resposta, pois não é a resposta correta. Iniciantes podem estar confusos.
Cxxl # 25/16
2
A que resposta você está se referindo? Não vejo um usuário com o nome "FJ" (nem mesmo nas respostas excluídas).
Peter Mortensen
3
l=[[0]*(L) for _ in range(W)]

Será mais rápido que:

l = [[0 for x in range(L)] for y in range(W)] 
Harsh Sharma
fonte
2
Resposta duplicada de uma já respondida abaixo. Também [[0]*(L) for i in range(W)]deve ser [[0]*(L) for _ in range(W)]uma vez que inão é usado em lugar algum
Ayush Vatsyayan
2

Você pode criar uma lista bidimensional vazia aninhando dois ou mais colchetes ou terceiro colchete ( []separados por vírgula) por um colchete , assim como abaixo:

Matrix = [[], []]

Agora, suponha que você queira anexar 1 Matrix[0][0]e digitar:

Matrix[0].append(1)

Agora, digite Matrix e pressione Enter. A saída será:

[[1], []]
Meraj al Maksud
fonte
1

Tente o seguinte:

rows = int(input('Enter rows\n'))
my_list = []
for i in range(rows):
    my_list.append(list(map(int, input().split())))
Ankit Sharma
fonte
1

Caso precise de uma matriz com números predefinidos, você pode usar o seguinte código:

def matrix(rows, cols, start=0):
    return [[c + start + r * cols for c in range(cols)] for r in range(rows)]


assert matrix(2, 3, 1) == [[1, 2, 3], [4, 5, 6]]
Vlad Bezden
fonte
1

Aqui está o trecho de código para criar uma matriz em python:

# get the input rows and cols
rows = int(input("rows : "))
cols = int(input("Cols : "))

# initialize the list
l=[[0]*cols for i in range(rows)]

# fill some random values in it
for i in range(0,rows):
    for j in range(0,cols):
        l[i][j] = i+j

# print the list
for i in range(0,rows):
    print()
    for j in range(0,cols):
        print(l[i][j],end=" ")

Por favor, sugira se eu perdi alguma coisa.

Chandra Shekhar
fonte