Come inizializzare un array bidimensionale in Python?


262

Sto iniziando Python e sto cercando di utilizzare un elenco bidimensionale, che inizialmente riempio con la stessa variabile in ogni luogo. Ho pensato a questo:

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

Dà il risultato desiderato, ma sembra una soluzione alternativa. Esiste un modo più semplice / più breve / più elegante per farlo?


7
Solo un piccolo (o significativo, a seconda di chi sta guardando) nitpick: le liste non sono array. Se si desidera array, utilizzare numpy.
Arnab Datta,

Questa domanda è simile : discute l'inizializzazione di array multidimensionali in Python.
Anderson Green,

@ArnabDatta Come inizializzeresti quindi un array multidimensionale in numpy?
Anderson Green,


Puoi disporre i dati in un array come la struttura in Python predefinito ma non è altrettanto efficiente o utile come un array NumPy. Soprattutto se si desidera gestire set di dati di grandi dimensioni. Ecco alcuni documenti docs.scipy.org/doc/numpy-1.10.1/user/basics.creation.html
jmdeamer

Risposte:


376

Un modello che spesso veniva fuori in Python era

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

che ha contribuito a motivare l'introduzione della comprensione dell'elenco, a cui convertire lo snippet

bar = [SOME EXPRESSION for item in some_iterable]

che è più breve e talvolta più chiaro. Di solito hai l'abitudine di riconoscerli e spesso di sostituire i cappi con delle comprensioni.

Il codice segue questo schema due volte

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 proposito, [[foo] * 10 per x in xrange (10)] può essere usato per sbarazzarsi di una comprensione. Il problema è che la moltiplicazione fa una copia superficiale, quindi new = [foo] * 10 new = [new] * 10 ti darà un elenco contenente lo stesso elenco dieci volte.
Scott Wolchok

8
Allo stesso modo, [foo] * 10è un elenco con le stesse esatte foo10 volte, che può essere o non essere importante.
Mike Graham,

2
possiamo usare la cosa più semplice: wtod_list = [[0 for x in xrange (10))] for x in xrange (10)]
indi60

2
Non fa mai male mostrare a qualcuno che aspetto ha un pesce.
Csteele5,

2
Per il commento di Mike Graham circa [foo] * 10: questo significa che questo sarebbe non funziona se si sta riempiendo un array con numeri casuali (Esamina [random.randint(1,2)] * 10a [1] * 10o [2] * 10che significa che si ottiene una matrice di tutti 1 o 2s, invece di un array casuale.
Tzu Li

225

È possibile utilizzare una comprensione dell'elenco :

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
poiché la dimensione (10) è la stessa, va bene, se non il ciclo nidificato deve venire prima [pippo per j nell'intervallo (range_of_j)] per i nell'intervallo (range_of_i)]
Dineshkumar

2
Questa risposta funziona bene, ma dato che ripetiamo iper righe e jcolonne, penso che dovrebbe essere meglio scambiare ie jnella tua sintassi per una migliore comprensione e cambiare l'intervallo in 2 numeri diversi.
DragonKnight,

139

Non usare [[v]*n]*n, è una trappola!

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

ma

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

funziona alla grande.


26
sì, sono caduto anche in questa trappola. È perché *sta copiando addressl'oggetto (elenco).
chinuy,

1
Ho votato perché mi ha preso. Per essere più chiari, [[0] * col for _ in range(row)].
Abhijit Sarkar il

138

In questo modo è più veloce della comprensione dell'elenco nidificato

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

Ecco alcuni tempi di Python3, per liste piccole e grandi

$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

Spiegazione:

[[foo]*10]*10crea un elenco dello stesso oggetto ripetuto 10 volte. Non puoi semplicemente usarlo, perché la modifica di un elemento modificherà lo stesso elemento in ogni riga!

x[:] è equivalente a list(X) ma è un po 'più efficiente poiché evita la ricerca del nome. Ad ogni modo, crea una copia superficiale di ogni riga, quindi ora tutti gli elementi sono indipendenti.

Tutti gli elementi sono però lo stesso foooggetto, quindi se fooè mutabile , non puoi usare questo schema. Dovresti usare

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

o assumendo una classe (o funzione) Foo che restituisce foos

[[Foo() for x in range(10)] for y in range(10)]

4
@ Mike, ti sei perso la parte in grassetto? se foo è mutevole, nessuna delle altre risposte qui funziona (a meno che tu non stia mutando foo)
John La Rooy,

1
Non è possibile copiare correttamente oggetti arbitrari utilizzando copy.deepcopy. È necessario un piano specifico per i dati se si dispone di un oggetto mutabile arbitrario.
Mike Graham,

1
Se hai bisogno di velocità che male in un ciclo, potrebbe essere il momento di usare Cython, tessere, o simili ...
james.haggerty

1
@JohnLaRooy penso che tu abbia scambiato xe y. Non dovrebbe essere[[copy.deepcopy(foo) for y in range(10)] for x in range(10)]
user3085931

1
@Nils [foo]*10non crea 10 oggetti diversi, ma è facile trascurare la differenza nel caso in cui foo sia immutabile, come un into str.
John La Rooy,

62

Per inizializzare un array bidimensionale in Python:

a = [[0 for x in range(columns)] for y in range(rows)]

4
Per inizializzare tutti i valori su 0, basta usare a = [[0 for x in range(columns)] for y in range(rows)].
ZX9,

28
[[foo for x in xrange(10)] for y in xrange(10)]

1
xrange () è stato rimosso in python3.5
MiaeKim il

perché questo non funziona: [0 * col] * riga. Quando modifico qualche elemento, questo si replica in altri punti. Ma non capisco perché?
code muncher,

Perché fa esattamente la stessa cosa del codice nella domanda.
Ignacio Vazquez-Abrams,

2
@codemuncher Il motivo che [[0] * col] * rownon fa quello che vuoi è perché quando inizializzi un elenco 2d in quel modo, Python non creerà copie distinte di ogni riga. Verrà invece avviato l'elenco esterno con i puntatori alla stessa copia di [0]*col. Qualsiasi modifica apportata a una delle righe verrà quindi riflessa nelle restanti righe poiché tutte puntano effettivamente agli stessi dati in memoria.
Addie,

Solo un pensiero, ma tutte queste liste non sono utili per l'aggiunta? Vale a dire. se desidero un elenco 2D vuoto della dimensione 3 * 6 e voglio aggiungere all'indice [0] [0], [1] [0], [2] [0] e così via per riempire tutti i 18 elementi, nessuno di queste risposte funzioneranno bene?
mLstudent33

22

Di solito, quando si desidera un array multidimensionale, non si desidera un elenco di elenchi, ma piuttosto un array intorpidito o possibilmente un dict.

Ad esempio, con numpy faresti qualcosa di simile

import numpy
a = numpy.empty((10, 10))
a.fill(foo)

2
Anche se numpyè fantastico, penso che potrebbe essere un po 'eccessivo per un principiante.
Esteban Küber

3
numpy fornisce un tipo di array multidimensionale. Costruire un buon array multidimensionale fuori dagli elenchi è possibile ma meno utile e più difficile per un principiante rispetto all'utilizzo del numpy. Gli elenchi nidificati sono ottimi per alcune applicazioni, ma di solito non sono quelli con cui chi vorrebbe un array 2d sarebbe meglio.
Mike Graham,

1
dopo alcuni anni di occasionali app di python serie, le stranezze delle matrici standard di Python sembrano giustificare il fatto di andare avanti numpy. +1
javadba

12

Puoi fare solo questo:

[[element] * numcols] * numrows

Per esempio:

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

Ma questo ha un effetto collaterale indesiderato:

>>> 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
Nella mia esperienza, questo effetto "indesiderabile" è spesso fonte di alcuni errori logici molto gravi. Secondo me, questo approccio dovrebbe essere evitato, invece la risposta di Vipul è molto meglio.
Alan Turing,

questo approccio funziona bene, perché nei commenti alcune persone riferiscono che è così male?
Bravo,

1
A causa dell'effetto collaterale sottostimato, non puoi davvero trattarlo come una matrice. Se non è necessario modificare i contenuti, allora andrà tutto bene.
hithwen,

9
twod_list = [[foo for _ in range(m)] for _ in range(n)]

poiché n è il numero di righe e m è il numero di colonna e foo è il valore.


8

Se è un array scarsamente popolato, potresti stare meglio usando un dizionario con una tupla:

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

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

per ogni elemento [0]*10verrà creato un nuovo ..


4

Approccio errato: [[None * 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

Con questo approccio, python non consente la creazione di spazi di indirizzi diversi per le colonne esterne e porterà a un comportamento scorretto diverso da quello previsto.

Approccio corretto ma con eccezione:

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

È un buon approccio ma c'è un'eccezione se si imposta il valore predefinito su 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

Quindi imposta correttamente il tuo valore predefinito usando questo approccio.

Assoluto corretto:

Segui la risposta del microfono del doppio loop .


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

1
Mentre questo codice può rispondere alla domanda, fornendo un contesto aggiuntivo riguardo al perché e / o al modo in cui questo codice risponde alla domanda migliora il suo valore a lungo termine.
Ajean


3

usa il pensiero più semplice per crearlo.

wtod_list = []

e aggiungi le dimensioni:

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

o se vogliamo dichiarare la dimensione in primo luogo. usiamo solo:

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

1

Come sottolineato da @Arnab e @Mike, un array non è un elenco. Poche differenze sono 1) le matrici hanno dimensioni fisse durante l'inizializzazione 2) le matrici normalmente supportano operazioni minori di un elenco.

Forse un eccesso nella maggior parte dei casi, ma qui c'è un'implementazione di base dell'array 2d che sfrutta l'implementazione dell'array hardware usando i ptyon ctypes (librerie 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

La cosa importante che ho capito è: Durante l'inizializzazione di un array (in qualsiasi dimensione) Dovremmo dare un valore predefinito a tutte le posizioni dell'array. Quindi viene completata solo l'inizializzazione. Successivamente, possiamo modificare o ricevere nuovi valori in qualsiasi posizione dell'array. Il codice seguente ha funzionato perfettamente per me

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 si utilizza Numpy , è possibile creare facilmente array 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)]]

Quanto sopra ti darà un array 2D 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]]

Sta usando la comprensione dell'elenco nidificato. Ripartizione come di seguito:

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

[x] * col -> espressione finale valutata
per x in -> x sarà il valore fornito dall'iteratore
[b per b nell'intervallo (riga)]] -> Iteratore.

[b per b nell'intervallo (riga)]] questo valuterà a [0,1,2,3,4] poiché riga = 5,
quindi ora semplifica

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

Questo valuterà a [[0] * 5 per x in [0,1,2,3,4]] -> con x = 0 1a iterazione
[[1] * 5 per x in [0,1,2, 3,4]] -> con x = 1 2a iterazione
[[2] * 5 per x in [0,1,2,3,4]] -> con x = 2 3a iterazione
[[3] * 5 per x in [0,1,2,3,4]] -> con x = 3 4a iterazione
[[4] * 5 per x in [0,1,2,3,4]] -> con x = 4 quinta iterazione


0

Questo è il migliore che ho trovato per insegnare ai nuovi programmatori e senza usare librerie aggiuntive. Vorrei qualcosa di meglio però.

def initialize_twodlist(value):
    list=[]
    for row in range(10):
        list.append([value]*10)
    return list

0

Ecco un modo più semplice:

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

Per inizializzare tutte le celle con qualsiasi valore 'x' usare:

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

0

Spesso utilizzo questo approccio per inizializzare un array bidimensionale

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


0

Il modello generale per aggiungere quote potrebbe essere disegnato da questa serie:

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)

Benvenuti in SO. Questa domanda ha già una risposta accettata ampiamente votata. A prima vista, questo post in realtà non risponde alla domanda. Consulta stackoverflow.com/help/how-to-answer per assistenza.
Nick,

0

Puoi provare questo [[0] * 10] * 10. Ciò restituirà la matrice 2d di 10 righe e 10 colonne con valore 0 per ogni cella.


Questo è essenzialmente la stessa risposta stackoverflow.com/a/25601284/2413201 ...
Armali

2
Questo crea una matrice di 10 puntatori sulla stessa riga. Se lo fai a = [[0]*10]*10e a[0][0] = 1vedrai quel primo elemento in ogni riga ora uguale a 1
andnik

0

lst = [[0] * m per i nell'intervallo (n)]

inizializza tutta la matrice n = righe e m = colonne


Potete per favore formattare il codice come codice? Sarebbe molto più leggibile.
Thomas,

0

Un altro modo è quello di utilizzare un dizionario per contenere un array bidimensionale.

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

Questo può contenere qualsiasi valore 1D, 2D e per inizializzare questo 0o qualsiasi altro valore int, utilizzare le raccolte .

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

0

Codice:

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 essere immutabile.


-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
Aggiungi un testo che descriva cosa fa il tuo codice.
whackamadoodle3000,

1
Di solito è meglio spiegare una soluzione invece di pubblicare solo alcune righe di codice anonimo. Puoi leggere Come posso scrivere una buona risposta , e anche Spiegare risposte interamente basate su codice .
Massimiliano Kraus,
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.