Como inicializar uma matriz bidimensional em Python?

262

Estou iniciando python e estou tentando usar uma lista bidimensional, que inicialmente preenchei com a mesma variável em todos os lugares. Eu vim com isso:

def initialize_twodlist(foo):
    twod_list = []
    new = []
    for i in range (0, 10):
        for j in range (0, 10):
            new.append(foo)
        twod_list.append(new)
        new = []

Ele fornece o resultado desejado, mas parece uma solução alternativa. Existe uma maneira mais fácil / mais curta / mais elegante de fazer isso?

thepandaatemyface
fonte
7
Apenas um pequeno (ou significativo, dependendo de quem está assistindo) nitpick: listas não são matrizes. Se você deseja matrizes, use numpy.
Arnab Datta
Esta pergunta é semelhante : discute a inicialização de matrizes multidimensionais em Python.
Anderson Green
@ArnabDatta Como você inicializaria uma matriz multidimensional em numpy?
Anderson Green
1
@AndersonGreen docs.scipy.org/doc/numpy/user/…
Arnab Datta
Você pode organizar dados em uma matriz como estrutura no Python padrão, mas não é tão eficiente ou útil quanto uma matriz NumPy. Especialmente se você quiser lidar com grandes conjuntos de dados. Aqui está alguma documentação docs.scipy.org/doc/numpy-1.10.1/user/basics.creation.html
jmdeamer

Respostas:

376

Um padrão que muitas vezes surgiu em Python foi

bar = []
for item in some_iterable:
    bar.append(SOME EXPRESSION)

que ajudou a motivar a introdução de compreensões de lista, que convertem esse snippet em

bar = [SOME EXPRESSION for item in some_iterable]

que é mais curto e às vezes mais claro. Geralmente, você tem o hábito de reconhecê-las e frequentemente substituir loops por compreensões.

Seu código segue esse padrão duas vezes

twod_list = []                                       \                      
for i in range (0, 10):                               \
    new = []                  \ can be replaced        } this too
    for j in range (0, 10):    } with a list          /
        new.append(foo)       / comprehension        /
    twod_list.append(new)                           /
Mike Graham
fonte
35
A propósito, [[foo] * 10 para x em xrange (10)] pode ser usado para se livrar de uma compreensão. O problema é que a multiplicação faz uma cópia superficial, então new = [foo] * 10 new = [new] * 10 fornece uma lista contendo a mesma lista dez vezes.
Scott Wolchok
8
Da mesma forma, [foo] * 10é uma lista com as mesmas exatas foo10 vezes, o que pode ou não ser importante.
Mike Graham
2
podemos usar a coisa mais simples: wtod_list = [[0 para x em xrange (10))] para x em xrange (10)]
indi60
2
Nunca é demais mostrar a alguém como é um peixe.
Csteele5
2
Para o comentário de Mike Graham sobre [foo] * 10: Isto significa que este não iria funcionar se você está preenchendo uma matriz com números aleatórios (avalia [random.randint(1,2)] * 10a [1] * 10ou [2] * 10que significa que você começa uma matriz de todos 1s ou 2s, em vez de uma matriz aleatória.
Tzu Li
225

Você pode usar uma compreensão de lista :

x = [[foo for i in range(10)] for j in range(10)]
# x is now a 10x10 array of 'foo' (which can depend on i and j if you want)
Adam Rosenfield
fonte
1
uma vez que o tamanho (10) é igual a sua fina, se não o loop aninhado tem que estar em primeiro lugar [foo para j na gama (range_of_j)] para i na gama (range_of_i)]
Dineshkumar
2
Essa resposta funciona bem, mas como iteramos ipara linhas e jcolunas, acho que deve ser melhor trocar ie jna sua sintaxe para melhor compreensão e alterar o intervalo para 2 números diferentes.
DragonKnight 20/10
139

Não use [[v]*n]*n, é uma armadilha!

>>> a = [[0]*3]*3
>>> a
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> a[0][0]=1
>>> a
[[1, 0, 0], [1, 0, 0], [1, 0, 0]]

mas

    t = [ [0]*3 for i in range(3)]

funciona bem.

Jason CHAN
fonte
26
sim, eu caí nessa armadilha também. É porque *está copiando addresso objeto (lista).
19717 chinuy
1
Voto positivo, uma vez que isso me pegou. Para ser mais claro [[0] * col for _ in range(row)].
Abhijit Sarkar
138

Dessa maneira, é mais rápido que as compreensões de lista aninhadas

[x[:] for x in [[foo] * 10] * 10]    # for immutable foo!

Aqui estão alguns horários do python3, para listas pequenas e grandes

$python3 -m timeit '[x[:] for x in [[1] * 10] * 10]'
1000000 loops, best of 3: 1.55 usec per loop

$ python3 -m timeit '[[1 for i in range(10)] for j in range(10)]'
100000 loops, best of 3: 6.44 usec per loop

$ python3 -m timeit '[x[:] for x in [[1] * 1000] * 1000]'
100 loops, best of 3: 5.5 msec per loop

$ python3 -m timeit '[[1 for i in range(1000)] for j in range(1000)]'
10 loops, best of 3: 27 msec per loop

Explicação:

[[foo]*10]*10cria uma lista do mesmo objeto repetida 10 vezes. Você não pode simplesmente usar isso, porque modificar um elemento modificará o mesmo elemento em cada linha!

x[:]é equivalente a, list(X)mas é um pouco mais eficiente, pois evita a pesquisa de nome. De qualquer maneira, ele cria uma cópia superficial de cada linha; portanto, agora todos os elementos são independentes.

Todos os elementos são o mesmo fooobjeto; portanto, se fooé mutável , você não pode usar esse esquema.

import copy
[[copy.deepcopy(foo) for x in range(10)] for y in range(10)]

ou assumindo uma classe (ou função) Fooque retorna foos

[[Foo() for x in range(10)] for y in range(10)]
John La Rooy
fonte
4
@ Mike, você perdeu o papel em negrito? se foo é mutável, nenhuma das outras respostas aqui trabalhar (a menos que você não está mutando foo em tudo)
John La Rooy
1
Você não pode copiar corretamente objetos arbitrários usando copy.deepcopy. Você precisa de um plano específico para seus dados se tiver um objeto mutável arbitrário.
Mike Graham
1
Se você precisa de velocidade que mal em um loop, pode ser hora de usar Cython, tecer, ou similar ...
james.haggerty
1
@JohnLaRooy eu acho que você trocou xe y. Não deveria ser[[copy.deepcopy(foo) for y in range(10)] for x in range(10)]
#
1
O @Nils [foo]*10não cria 10 objetos diferentes - mas é fácil ignorar a diferença no caso de foo ser imutável, como um intou str.
John La Rooy 6/18
62

Para inicializar uma matriz bidimensional em Python:

a = [[0 for x in range(columns)] for y in range(rows)]
Vipul
fonte
4
Para inicializar todos os valores para 0, basta usar a = [[0 for x in range(columns)] for y in range(rows)].
ZX9 21/09/16
28
[[foo for x in xrange(10)] for y in xrange(10)]
Ignacio Vazquez-Abrams
fonte
1
O xrange () foi removido no python3.5
MiaeKim 6/16
por que isso não funciona: [0 * col] * row. Quando modifico algum elemento, ele se replica em outros lugares. Mas eu não entendo o porquê?
code muncher
Porque isso faz exatamente a mesma coisa que o código da pergunta.
Ignacio Vazquez-Abrams
2
@codemuncher O motivo que [[0] * col] * rownão faz o que você quer é porque, quando você inicializa uma lista 2D dessa maneira, o Python não cria cópias distintas de cada linha. Em vez disso, iniciará a lista externa com ponteiros para a mesma cópia de [0]*col. Qualquer edição que você fizer em uma das linhas será refletida nas linhas restantes, pois na verdade elas estão apontando para os mesmos dados na memória.
Addie
Apenas um pensamento, mas todas essas listas não são boas para acrescentar? Ou seja. se eu quiser uma lista 2D vazia da dimensão 3 * 6 e desejar acrescentar ao índice [0] [0], [1] [0], [2] [0] e assim por diante para preencher todos os 18 elementos, nenhum dos essas respostas vão funcionar certo?
mLstudent33
22

Geralmente, quando você deseja matrizes multidimensionais, não deseja uma lista de listas, mas sim uma matriz numpy ou, possivelmente, um ditado.

Por exemplo, com numpy você faria algo como

import numpy
a = numpy.empty((10, 10))
a.fill(foo)
Mike Graham
fonte
2
Embora numpyseja ótimo, acho que pode ser um pouco exagerado para um iniciante.
Esteban Kuber
3
numpy fornece um tipo de matriz multidimensional. Criar uma boa matriz multidimensional a partir de listas é possível, mas menos útil e mais difícil para um iniciante do que usar numpy. Listas aninhadas são ótimas para alguns aplicativos, mas geralmente não são as melhores opções para quem deseja uma matriz 2D.
Mike Graham
1
depois de alguns anos fazendo aplicativos python sérios, as peculiaridades das matrizes python padrão parecem justificar o avanço numpy. 1
javadba
12

Você pode fazer exatamente isso:

[[element] * numcols] * numrows

Por exemplo:

>>> [['a'] *3] * 2
[['a', 'a', 'a'], ['a', 'a', 'a']]

Mas isso tem um efeito colateral indesejado:

>>> b = [['a']*3]*3
>>> b
[['a', 'a', 'a'], ['a', 'a', 'a'], ['a', 'a', 'a']]
>>> b[1][1]
'a'
>>> b[1][1] = 'b'
>>> b
[['a', 'b', 'a'], ['a', 'b', 'a'], ['a', 'b', 'a']]
hithwen
fonte
11
Na minha experiência, esse efeito "indesejável" geralmente é fonte de alguns erros lógicos muito ruins. Na minha opinião, essa abordagem deve ser evitada. Em vez disso, a resposta da @ Vipul é muito melhor.
Alan Turing
essa abordagem funciona bem, por que nos comentários algumas pessoas referem que é tão ruim?
Bravo
1
Por causa do efeito colateral não desejado, você realmente não pode tratá-lo como uma matriz. Se você não precisar alterar o conteúdo, tudo ficará bem.
hithwen 22/11/19
9
twod_list = [[foo for _ in range(m)] for _ in range(n)]

pois n é o número de linhas e m é o número de colunas e foo é o valor.

Moustafa Saleh
fonte
8

Se for uma matriz pouco povoada, é melhor usar um dicionário digitado com uma tupla:

dict = {}
key = (a,b)
dict[key] = value
...
BTK
fonte
5
t = [ [0]*10 for i in [0]*10]

para cada elemento, um novo [0]*10será criado.

user9269722
fonte
4

Abordagem incorreta: [[Nenhum * m] * n]

>>> m, n = map(int, raw_input().split())
5 5
>>> x[0][0] = 34
>>> x
[[34, None, None, None, None], [34, None, None, None, None], [34, None, None, None, None], [34, None, None, None, None], [34, None, None, None, None]]
>>> id(x[0][0])
140416461589776
>>> id(x[3][0])
140416461589776

Com essa abordagem, o python não permite a criação de espaço de endereço diferente para as colunas externas e levará a vários comportamentos inadequados que a sua expectativa.

Abordagem correta, mas com exceção:

y = [[0 for i in range(m)] for j in range(n)]
>>> id(y[0][0]) == id(y[1][0])
False

É uma boa abordagem, mas há exceção se você definir o valor padrão como None

>>> r = [[None for i in range(5)] for j in range(5)]
>>> r
[[None, None, None, None, None], [None, None, None, None, None], [None, None, None, None, None], [None, None, None, None, None], [None, None, None, None, None]]
>>> id(r[0][0]) == id(r[2][0])
True

Portanto, defina seu valor padrão corretamente usando essa abordagem.

Absoluto correto:

Siga a resposta do microfone de loop duplo .

patilnitin
fonte
3
Matrix={}
for i in range(0,3):
  for j in range(0,3):
    Matrix[i,j] = raw_input("Enter the matrix:")
Sparsh
fonte
1
Embora esse código possa responder à pergunta, fornecer um contexto adicional a respeito de por que e / ou como esse código responde à pergunta melhora seu valor a longo prazo.
Ajean 8/03/16
3

Para inicializar uma matriz bidimensional, use: arr = [[]*m for i in range(n)]

na verdade, arr = [[]*m]*ncriará uma matriz 2D na qual todas as n matrizes apontarão para a mesma matriz, portanto, qualquer alteração no valor em qualquer elemento será refletida em todas as n listas

para mais explicações, visite: https://www.geeksforgeeks.org/python-using-2d-arrays-lists-the-right-way/

Abhimanyu
fonte
3

use o pensamento mais simples para criar isso.

wtod_list = []

e adicione o tamanho:

wtod_list = [[0 for x in xrange(10)] for x in xrange(10)]

ou se quisermos declarar o tamanho em primeiro lugar. nós usamos apenas:

   wtod_list = [[0 for x in xrange(10)] for x in xrange(10)]
indi60
fonte
1

Como @Arnab e @Mike apontaram, uma matriz não é uma lista. Poucas diferenças são 1) matrizes com tamanho fixo durante a inicialização 2) matrizes normalmente suportam operações menores que uma lista.

Talvez um exagero na maioria dos casos, mas aqui está uma implementação básica da matriz 2D que aproveita a implementação da matriz de hardware usando ctypes python (bibliotecas c)

import ctypes
class Array:
    def __init__(self,size,foo): #foo is the initial value
        self._size = size
        ArrayType = ctypes.py_object * size
        self._array = ArrayType()
        for i in range(size):
            self._array[i] = foo
    def __getitem__(self,index):
        return self._array[index]
    def __setitem__(self,index,value):
        self._array[index] = value
    def __len__(self):
        return self._size

class TwoDArray:
    def __init__(self,columns,rows,foo):
        self._2dArray = Array(rows,foo)
        for i in range(rows):
            self._2dArray[i] = Array(columns,foo)

    def numRows(self):
        return len(self._2dArray)
    def numCols(self):
        return len((self._2dArray)[0])
    def __getitem__(self,indexTuple):
        row = indexTuple[0]
        col = indexTuple[1]
        assert row >= 0 and row < self.numRows() \
               and col >=0 and col < self.numCols(),\
               "Array script out of range"
        return ((self._2dArray)[row])[col]

if(__name__ == "__main__"):
    twodArray = TwoDArray(4,5,5)#sample input
    print(twodArray[2,3])
Antony Thomas
fonte
1

O importante que entendi é: Ao inicializar uma matriz (em qualquer dimensão), devemos atribuir um valor padrão a todas as posições da matriz. Somente a inicialização é concluída. Depois disso, podemos alterar ou receber novos valores para qualquer posição da matriz. O código abaixo funcionou perfeitamente para mim

N=7
F=2

#INITIALIZATION of 7 x 2 array with deafult value as 0
ar=[[0]*F for x in range(N)]

#RECEIVING NEW VALUES TO THE INITIALIZED ARRAY
for i in range(N):
    for j in range(F):
        ar[i][j]=int(input())
print(ar)
Fairoos Ok
fonte
1

Se você usa o numpy , pode criar facilmente matrizes 2D:

import numpy as np

row = 3
col = 5
num = 10
x = np.full((row, col), num)

x

array([[10, 10, 10, 10, 10],
       [10, 10, 10, 10, 10],
       [10, 10, 10, 10, 10]])
Mehmet Emin Yıldırım
fonte
1
row=5
col=5
[[x]*col for x in [b for b in range(row)]]

O exemplo acima fornece uma matriz 2D de 5x5

[[0, 0, 0, 0, 0],
 [1, 1, 1, 1, 1],
 [2, 2, 2, 2, 2],
 [3, 3, 3, 3, 3],
 [4, 4, 4, 4, 4]]

Está usando compreensão de lista aninhada. Repartição como abaixo:

[[x]*col for x in [b for b in range(row)]]

[x] * col -> expressão final avaliada
para x em -> x será o valor fornecido pelo iterador
[b para b no intervalo (linha)]] -> iterador.

[b para b no intervalo (linha)]] isso será avaliado para [0,1,2,3,4], pois linha = 5
, agora simplifica a

[[x]*col for x in [0,1,2,3,4]]

Isso será avaliado em [[0] * 5 para x em [0,1,2,3,4]] -> com x = 0 1ª iteração
[[1] * 5 para x em [0,1,2, 3,4]] -> com x = 1 2ª iteração
[[2] * 5 para x em [0,1,2,3,4]] -> com x = 2 3ª iteração
[[3] * 5 para x em [0,1,2,3,4]] -> com x = 3 4ª iteração
[[4] * 5 para x em [0,1,2,3,4]] -> com x = 4 5a iteração

Satya
fonte
0

Este é o melhor que eu encontrei para ensinar novos programadores e sem usar bibliotecas adicionais. Eu gostaria de algo melhor.

def initialize_twodlist(value):
    list=[]
    for row in range(10):
        list.append([value]*10)
    return list
Paul Vincent Craven
fonte
0

Aqui está uma maneira mais fácil:

import numpy as np
twoD = np.array([[]*m]*n)

Para inicializar todas as células com qualquer valor 'x', use:

twoD = np.array([[x]*m]*n
user3650331
fonte
0

Muitas vezes eu uso essa abordagem para inicializar uma matriz bidimensional

n=[[int(x) for x in input().split()] for i in range(int(input())]


fonte
0

O padrão geral para adicionar dimensões pode ser desenhado a partir desta série:

x = 0
mat1 = []
for i in range(3):
    mat1.append(x)
    x+=1
print(mat1)


x=0
mat2 = []
for i in range(3):
    tmp = []
    for j in range(4):
        tmp.append(x)
        x+=1
    mat2.append(tmp)

print(mat2)


x=0
mat3 = []
for i in range(3):
    tmp = []
    for j in range(4):
        tmp2 = []
        for k in range(5):
            tmp2.append(x)
            x+=1
        tmp.append(tmp2)
    mat3.append(tmp)

print(mat3)
juanfal
fonte
Bem-vindo ao SO. Esta pergunta já tem uma resposta aceita massivamente votada para cima. À primeira vista, este post não responde à pergunta. Consulte stackoverflow.com/help/how-to-answer para obter orientação.
24418 Nick
0

Você pode tentar isso [[0] * 10] * 10. Isso retornará a matriz 2D de 10 linhas e 10 colunas com o valor 0 para cada célula.

ishant
fonte
Esta é essencialmente a mesma resposta que stackoverflow.com/a/25601284/2413201 ...
Armali
2
Isso cria uma matriz de 10 ponteiros para a mesma linha. Se você fizer isso a = [[0]*10]*10e, em seguida, a[0][0] = 1você vai ver que primeiro elemento em cada linha agora igual a 1
andnik
0

lst = [[0] * m para i no intervalo (n)]

inicialize todas as matrizes n = linhas e m = colunas

HRITIK RAJENDRA AKOLKAR
fonte
Você pode formatar o código como código? Seria muito mais legível.
Thomas
0

Outra maneira é usar um dicionário para armazenar uma matriz bidimensional.

twoD = {}
twoD[0,0] = 0
print(twoD[0,0]) # ===> prints 0

Isso pode conter apenas valores 1D, 2D e, para inicializar esse valor 0ou qualquer outro valor int, use coleções .

import collections
twoD = collections.defaultdict(int)
print(twoD[0,0]) # ==> prints 0
twoD[1,1] = 1
print(twoD[1,1]) # ==> prints 1
Tej91
fonte
0

Código:

num_rows, num_cols = 4, 2
initial_val = 0
matrix = [[initial_val] * num_cols for _ in range(num_rows)]
print(matrix) 
# [[0, 0], [0, 0], [0, 0], [0, 0]]

initial_val deve ser imutável.

Abhishek Bhatia
fonte
-3
from random import randint
l = []

for i in range(10):
    k=[]
    for j in range(10):
        a= randint(1,100)
        k.append(a)

    l.append(k)




print(l)
print(max(l[2]))

b = []
for i in range(10):
    a = l[i][5]
    b.append(a)

print(min(b))
KANDARP JAYESH SHAH
fonte
4
Por favor, adicione algum texto descrevendo o que seu código faz.
whackamadoodle3000
1
Geralmente, é melhor explicar uma solução em vez de apenas postar algumas linhas de código anônimo. Você pode ler Como redigir uma boa resposta e também Explicar respostas inteiramente baseadas em código .
Massimiliano Kraus