Come definire un array bidimensionale in Python


726

Voglio definire un array bidimensionale senza una lunghezza inizializzata come questa:

Matrix = [][]

ma non funziona ...

Ho provato il codice qui sotto, ma è anche sbagliato:

Matrix = [5][5]

Errore:

Traceback ...

IndexError: list index out of range

Qual è il mio errore?


14
Non si definiscono gli array o qualsiasi altra cosa. Tuttavia, puoi creare sequenze multidimensionali, come mostrano le risposte qui. Ricorda che le variabili Python non sono tipizzate, ma i valori sono fortemente tipizzati.
SingleNegationElimination,

1
Non ho capito bene. Proveniente da altre lingue: è una differenza tra un array 1D contenente array 1D e un array 2D. E AFAIK non c'è modo di avere un array multidimensionale (o elenco) in Python. Dovrebbe essere detto qui ...
Dirk Reichel,

Risposte:


1011

Stai tecnicamente cercando di indicizzare un array non inizializzato. Devi prima inizializzare l'elenco esterno con gli elenchi prima di aggiungere elementi; Python chiama questa "comprensione della 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)] 

Ora puoi aggiungere elementi all'elenco:

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

Si noti che la matrice è l'indirizzo "y" maggiore, in altre parole, l '"indice y" precede l' "indice x".

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

Anche se puoi nominarli come desideri, lo guardo in questo modo per evitare un po 'di confusione che potrebbe sorgere con l'indicizzazione, se usi "x" per entrambi gli elenchi interno ed esterno e desideri una matrice non quadrata.


219
[[0 per x in range (cols_count)] per x in range (rows_count)]
songhir

3
Strana modifica di ademar111190. In Python 3 non c'è xrange ma se devi usare Python 2 allora xrange è la funzione corretta da usare se non vuoi creare inutilmente oggetti.
Dave,

4
@dave Se non è necessario il riempimento zero, è possibile utilizzare rangeper creare direttamente gli elenchi interni:[range(5) for x in range(5)]
alanjds

2
@alanjds: è vero, ma crei potenzialmente molti riferimenti a oggetti non necessari in Python 2 per l'iterazione esterna (prova questo con un intervallo MOLTO ampio). Inoltre, l'inizializzazione di un certo valore è quasi sempre ciò che si desidera - e questo è il più delle volte 0. L'intervallo produce una raccolta iterabile - xrange restituisce un generatore. Il mio punto era che Ademar "correggeva" qualcosa che in realtà era più generalmente corretto ed efficiente della sua correzione.
Dave,

10
@ 6packkid la [0] * wparte è bella, ma [[0] * w] * h]produrrà comportamenti inaspettati. Prova 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,

408

Se vuoi davvero una matrice, potresti usare meglio numpy. Le operazioni con le matrici nella numpymaggior parte dei casi usano un tipo di array con due dimensioni. Esistono molti modi per creare un nuovo array; una delle più utili è la zerosfunzione, che accetta un parametro di forma e restituisce un array di una determinata forma, con i valori inizializzati su 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.]])

Ecco alcuni altri modi per creare matrici e matrici 2-d (con output rimosso per compattezza):

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

numpyfornisce anche un matrixtipo, ma non è più raccomandato per alcun uso e potrebbe essere rimosso numpyin futuro.


80
Ogni volta che vuoi matrici, vuoi usare numpy. Questa risposta dovrebbe essere la prima.
Pat B,

3
Il fatto che la domanda usi la parola inglese "matrice" non significa che dovrebbero usarlo np.matrixper rappresentarla. Il modo corretto di rappresentare una matrice in numpy è con un array.
user2357112 supporta Monica il

@ user2357112, E come puoi vedere, la maggior parte degli esempi sopra elencati produce arrayinvece di matrici. Anche se non è sempre incoraggiato, ci sono motivi legittimi per l'uso matrix- questioni di contesto.
mittente

1
@senderle, puoi espandere i motivi per utilizzare matrix? Da quando è @stato introdotto l'operatore, sembra esserci un motivo in meno da quando questo post è stato scritto.
jpp

1
@jpp, come diceva il post in precedenza, le persone provenienti da Matlab potrebbero trovarlo utile. Ma i numpydocumenti ora indicano che la classe potrebbe essere deprecata e rimossa in futuro, quindi l'ho tolta dalla risposta.
mittente

337

Ecco una notazione più breve per l'inizializzazione di un elenco di elenchi:

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

Sfortunatamente accorciarlo a qualcosa del genere 5*[5*[0]]non funziona davvero perché finisci con 5 copie dello stesso elenco, quindi quando ne modifichi una cambiano tutte, per esempio:

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

4
Potresti spiegare la logica alla base del fallimento "accorciamento"? Perché python genera copie dello stesso elenco in questo caso e una matrice di celle diverse nel caso di [0]*5?
mike622867,

12
I commenti sopra non sono esattamente veri: [0] * 5 crea ancora una sequenza con 5 volte un riferimento allo stesso Oggetto che rappresenta il numero 0. Ma non lo noterai mai perché 0 è immutabile (direi che 0 si comporta come un valore - o potresti pensarlo come un tipo di dati primitivo - perché è immutabile, quindi non avrai mai problemi con riferimenti allo stesso oggetto invece di avere copie.)
dreua,

4
più pythonic: [[0]*5 for _ in range(5)]con il contatore loop anonimo non stai usando
Jean-François Fabre

Bello che tu indichi il problema della copia superficiale nel secondo esempio.
whatacold

grazie @dreua, ero davvero confuso su come funzioni [0]*5bene. Ora capisco perché [{0}]*8sarebbe una cattiva idea anche.
Kuku,

110

Se si desidera creare una matrice vuota, la sintassi corretta è

matrix = [[]]

E se vuoi generare una matrice di dimensione 5 riempita con 0,

matrix = [[0 for i in xrange(5)] for i in xrange(5)]

@KorayTugay Perché la matrice è rappresentata usando gli elenchi Python (le righe) nidificati all'interno di un altro elenco (le colonne).
partecipazione

2
Per Python-3 usa invece la funzione range invece xrange func
Rakesh Chaudhari,

77

Se tutto ciò che desideri è un contenitore bidimensionale per contenere alcuni elementi, puoi invece utilizzare un dizionario in modo conveniente:

Matrix = {}

Quindi puoi fare:

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

Questo funziona perché 1,2è una tupla e la stai usando come chiave per indicizzare il dizionario. Il risultato è simile a una matrice sparsa muta.

Come indicato da osa e Josap Valls, puoi anche utilizzare in Matrix = collections.defaultdict(lambda:0)modo che gli elementi mancanti abbiano un valore predefinito di 0.

Vatsal sottolinea inoltre che questo metodo probabilmente non è molto efficace per matrici di grandi dimensioni e dovrebbe essere utilizzato solo in parti non critiche del codice.


2
Quindi puoi anche fare import collections; Matrix = collections.defaultdict(float), per sostituire gli zeri con elementi non inizializzati.
osa,

2
L'accesso a un dict per tuple (1,2) come chiave non avrebbe una complessità nel caso peggiore di O (n). Come internamente avrebbe cancellato le tuple. Considerando che l'utilizzo di un array 2D darebbe O (1) complessità temporale per accedere all'indice [1,2]. Quindi usare dict per questo non dovrebbe essere una buona scelta.
Vatsal,

@Vatsal wiki.python.org/moin/TimeComplexity afferma che il caso medio è O (1), ma hai ragione sul caso peggiore. Ad ogni modo, a meno che tu non stia parlando di MOLTI ARTICOLI, non ti interesseresti di questa differenza. In effetti, sarei più preoccupato per la memoria che per il tempo di accesso.
enobayram,

Inoltre, cerchiamo sempre di evitare l'uso di dicts fino a quando la complessità complessiva dell'algoritmo è uguale o maggiore di O (n ^ 2). Dato che 'n' volte O (n) gli accessi darebbero una complessità O (n ^ 2).
Vatsal,

@enobayram, scusa ma non sono d'accordo. L'analisi asintotica darà sempre O (n ^ 2), se il caso peggiore O (n) accederà 'n' volte. Dove come analisi ammortizzata può dare un limite minore. E c'è un'enorme differenza tra il caso ammortizzato e il caso medio ... si prega di fare riferimento prima di fare ipotesi e commenti vaghi
Vatsal

42

In Python creerai un elenco di elenchi. Non è necessario dichiarare le dimensioni in anticipo, ma è possibile. Per esempio:

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

Ora matrice [0] [0] == 2 e matrice [1] [0] == 3. Puoi anche usare la sintassi di comprensione dell'elenco. Questo esempio lo utilizza due volte per creare un "elenco bidimensionale":

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

6
extendsarebbe utile anche nel primo caso: se inizi con m = [[]], allora potresti aggiungere alla lista interna (estendere una riga) con m[0].extend([1,2]), e aggiungere alla lista esterna (aggiungere una nuova riga) con m.append([3,4]), quelle operazioni ti lascerebbero con [[1, 2], [3, 4]].
askewchan,

22

La risposta accettata è buona e corretta, ma mi ci è voluto un po 'di tempo per capire che potevo anche usarla per creare un array completamente vuoto.

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

risultati in

[[], [], []]

22

Dovresti creare un elenco di elenchi e il modo migliore è utilizzare le comprensioni nidificate:

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

Nel tuo [5][5]esempio, stai creando un elenco con un numero intero "5" all'interno e provi ad accedere al suo quinto elemento, e questo genera naturalmente un IndexError perché non esiste un quinto elemento:

>>> l = [5]
>>> l[5]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

In realtà la sequenza per row_index ('i') e column_index ('j') sono le seguenti: '>>> matrix = [[0 per column_index nell'intervallo (5)] per row_index nell'intervallo (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)

Perché un codice così lungo, anche quello in Pythonte lo chiedi?

Molto tempo fa, quando non mi sentivo a mio agio con Python, ho visto le risposte a riga singola per la scrittura di matrici 2D e mi sono detto che non userò di nuovo la matrice 2-D in Python. (Quelle singole righe erano piuttosto spaventose e non mi davano alcuna informazione su cosa stesse facendo Python. Nota anche che non sono a conoscenza di queste scorciatoie.)

Ad ogni modo, ecco il codice per un principiante che proviene da C, CPP e Java

Nota per gli amanti e gli esperti di Python: per favore, non votare verso il basso solo perché ho scritto un codice dettagliato.


13

Una riscrittura per una facile lettura:

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

13

Uso:

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

* 5 per la prima dimensione funziona perché a questo livello i dati sono immutabili.


5
Probabilmente lo scriverei comematrix = [[0]*cols for _ in range(rows)]
Shital Shah il

12

Per dichiarare una matrice di zeri (uno):

numpy.zeros((x, y))

per esempio

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

o numpy.ones ((x, y)) ad es

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

Sono possibili anche tre dimensioni. ( http://www.astro.ufl.edu/~warner/prog/python.html vedi -> Array multidimensionali)


12

È così che di solito creo array 2D in Python.

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

Trovo che questa sintassi sia facile da ricordare rispetto all'uso di due per i loop in una comprensione dell'elenco.


11

Sono sul mio primo script Python ed ero un po 'confuso dall'esempio della matrice quadrata, quindi spero che l'esempio seguente ti aiuti a risparmiare un po' di tempo:

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

così che

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

10

Usando NumPy puoi inizializzare una matrice vuota in questo modo:

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

E successivamente aggiungi dati come questo:

mm = np.append(mm, [[1,2]], axis=1)

quali sarebbero i pro e i contro dell'utilizzo del numpy piuttosto che della "comprensione della lista"?
Revolucion per Monica

7

Ho letto in file separati da virgola come questo:

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

L'elenco "dati" è quindi un elenco di elenchi con dati di indice [riga] [col]


7

Se vuoi essere in grado di pensarlo come un array 2D anziché essere costretto a pensare in termini di un elenco di elenchi (molto più naturale secondo me), puoi fare quanto segue:

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

Il risultato è un elenco (non un array NumPy) e puoi sovrascrivere le singole posizioni con numeri, stringhe o altro.


sono numpy.matrixequivalenti a numpy.zerossenza zeri senza essere in elenco?
Revolucion per Monica

6

Ecco a cosa serve il dizionario !

matrix = {}

È possibile definire chiavi e valori in due modi:

matrix[0,0] = value

o

matrix = { (0,0)  : value }

Risultato:

   [ value,  value,  value,  value,  value],
   [ value,  value,  value,  value,  value],
   ...

6

Uso:

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

Penso che NumPy sia la strada da percorrere. Quanto sopra è generico se non si desidera utilizzare NumPy.


Mi piace questo tentativo di fare qualcosa di semplice con Python alla vaniglia senza usare numpy.
Rick Henderson,

4

usando la lista:

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

usando dict: puoi anche memorizzare queste informazioni nella tabella hash per una ricerca veloce come

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]};

matrix ['1'] ti darà il risultato in O (1) tempo

* nb : è necessario affrontare una collisione nella tabella hash


4

Se non disponi di informazioni sulle dimensioni prima di iniziare, crea due elenchi unidimensionali.

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

Memorizza l'intera riga nel 1 ° elenco. Una volta fatto, aggiungi l'elenco 1 all'elenco 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

Produzione:

Enter No Of Coordinates >4
[[522, 96], [378, 276], [349, 741], [238, 439]]

3
# Creates a list containing 5 lists initialized to 0
Matrix = [[0]*5]*5

Fai attenzione a questa breve espressione, vedi la spiegazione completa nella risposta di @ FJ


19
Fai attenzione in questo modo, perché Matrix[0], Matrix[1], ..., Matrix[4]tutti puntano allo stesso array, quindi dopo Matrix[0][0] = 3, ti aspetteresti Matrix[0][0] == Matrix[1][0] == ... == Matrix[4][0] == 3.
gongzhitaao,

1
Grazie gongzhitaao per il tuo commento. Se l'avessi letto, elier mi avrebbe risparmiato almeno mezz'ora .. Avere una matrice in cui ogni riga indica lo stesso posto in memoria non sembra essere molto utile, e se non sei consapevole di quello che stai facendo è persino pericoloso! Sono abbastanza sicuro che NON è quello che Masoud Abasian, che ha posto la domanda, vuole fare.
Adrian,

7
È necessario rimuovere questa risposta, poiché non è la risposta corretta. I principianti potrebbero essere confusi.
cxxl,

2
A quale risposta ti riferisci? Non vedo un utente con il nome "FJ" (nemmeno nelle risposte cancellate).
Peter Mortensen,

3
l=[[0]*(L) for _ in range(W)]

Sarà più veloce di:

l = [[0 for x in range(L)] for y in range(W)] 

2
Risposta duplicata di una già risposta di seguito. Inoltre [[0]*(L) for i in range(W)]dovrebbe essere [[0]*(L) for _ in range(W)]poiché inon viene utilizzato da nessuna parte
Ayush Vatsyayan

2

Puoi creare un elenco bidimensionale vuoto annidando due o più parentesi quadre o una terza parentesi ( [], separate da virgola) con una parentesi quadra, proprio come sotto:

Matrix = [[], []]

Supponiamo ora di voler aggiungere 1 per Matrix[0][0]poi digitare:

Matrix[0].append(1)

Ora digita Matrix e premi Invio. L'output sarà:

[[1], []]

1

Prova questo:

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

1

Nel caso in cui sia necessaria una matrice con numeri predefiniti, è possibile utilizzare il seguente codice:

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

1

Ecco lo snippet di codice per la creazione di una matrice in 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=" ")

Per favore, suggerisci se ho perso qualcosa.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.