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?


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


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)                           /

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)

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.


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)]

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)]

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)]

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)

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']]

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.


8

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

dict = {}
key = (a,b)
dict[key] = value
...

5
t = [ [0]*10 for i in [0]*10]

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


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 .


3
Matrix={}
for i in range(0,3):
  for j in range(0,3):
    Matrix[i,j] = raw_input("Enter the matrix:")

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

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)]

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])

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)

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]])

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


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

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

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())]


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)

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.


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


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

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.


-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))

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.