Jak zainicjować tablicę dwuwymiarową w Pythonie?

262

Zaczynam python i próbuję użyć dwuwymiarowej listy, którą początkowo wypełniam tą samą zmienną w każdym miejscu. Wymyśliłem to:

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

Daje pożądany efekt, ale wydaje się obejściem. Czy jest na to łatwiejszy / krótszy / bardziej elegancki sposób?

thepandaatemyface
źródło
7
Tylko mały (lub znaczący, w zależności od tego, kto ogląda) nitpick: listy nie są tablicami. Jeśli chcesz tablice, użyj numpy.
Arnab Datta
To pytanie jest podobne : omawia inicjalizację tablic wielowymiarowych w Pythonie.
Anderson Green,
@ArnabDatta Jak zatem zainicjowałbyś tablicę wielowymiarową w Numpy?
Anderson Green,
1
@AndersonGreen docs.scipy.org/doc/numpy/user/…
Arnab Datta
Możesz ustawić dane w strukturze tablicowej w domyślnym języku Python, ale nie jest to tak wydajne ani przydatne jak tablica NumPy. Zwłaszcza jeśli chcesz poradzić sobie z dużymi zestawami danych. Oto dokumentacja docs.scipy.org/doc/numpy-1.10.1/user/basics.creation.html
jmdeamer

Odpowiedzi:

376

Wzorem, który często pojawiał się w Pythonie, był

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

który pomógł zmotywować wprowadzenie wyrażeń listowych, które przekonwertują ten fragment

bar = [SOME EXPRESSION for item in some_iterable]

który jest krótszy, a czasem jaśniejszy. Zwykle przyzwyczajasz się do ich rozpoznawania i często zastępujesz pętle zrozumieniem.

Twój kod jest dwa razy zgodny z tym wzorcem

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
źródło
35
Nawiasem mówiąc, [[foo] * 10 dla x w xrange (10)] może być użyte do pozbycia się jednego zrozumienia. Problem polega na tym, że mnożenie wykonuje płytką kopię, więc new = [foo] * 10 new = [new] * 10 da ci listę zawierającą tę samą listę dziesięć razy.
Scott Wolchok,
8
Podobnie [foo] * 10jest lista z dokładnie taką samą foo10 razy, co może, ale nie musi być ważne.
Mike Graham,
2
możemy użyć najprostszej rzeczy: wtod_list = [[0 dla x w xrange (10))] dla x w xrange (10)]
indi60
2
Jednak nigdy nie boli pokazać komuś, jak wygląda ryba.
Csteele5
2
Komentarz Mike'a Grahama na temat [foo] * 10: Oznacza to, że to nie zadziała, jeśli wypełnisz tablicę liczbami losowymi (ocenia [random.randint(1,2)] * 10na [1] * 10lub [2] * 10co oznacza, że ​​otrzymujesz tablicę wszystkich 1 lub 2 zamiast losowej tablicy.
Tzu Li
224

Możesz użyć rozumienia listy :

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
źródło
1
ponieważ rozmiar (10) jest taki sam, jest w porządku, jeśli nie, zagnieżdżona pętla musi być pierwsza [foo dla jw zakresie (zakres_j)] dla i w zakresie (zakres_i)]
Dineshkumar
2
Ta odpowiedź działa dobrze, ale ponieważ iterujemy idla wierszy i jkolumn, myślę, że lepiej jest zamienić ii zastosować jskładnię, aby lepiej zrozumieć i zmienić zakres na 2 różne liczby.
DragonKnight,
138

Ta metoda jest szybsza niż interpretacja listy zagnieżdżonej

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

Oto niektóre czasy Python3 dla małych i dużych list

$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

Wyjaśnienie:

[[foo]*10]*10tworzy listę tego samego obiektu powtarzaną 10 razy. Nie możesz tego po prostu użyć, ponieważ modyfikacja jednego elementu spowoduje zmodyfikowanie tego samego elementu w każdym wierszu!

x[:]jest równoważne, list(X)ale jest nieco bardziej wydajne, ponieważ pozwala uniknąć wyszukiwania nazw. Tak czy inaczej, tworzy płytką kopię każdego wiersza, więc teraz wszystkie elementy są niezależne.

Wszystkie elementy są tym samym fooobiektem, więc jeśli foomożna go modyfikować , nie możesz użyć tego schematu., Musisz użyć

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

lub przyjęcie klasy (lub funkcji), Fooktóra zwraca foos

[[Foo() for x in range(10)] for y in range(10)]
John La Rooy
źródło
4
@Mike, czy tęskniłeś za pogrubioną częścią? jeśli foo jest zmienne, żadna z pozostałych odpowiedzi tutaj nie działa (chyba że w ogóle nie mutujesz foo)
John La Rooy
1
Nie można poprawnie skopiować dowolnych obiektów za pomocą copy.deepcopy. Potrzebujesz planu specyficznego dla swoich danych, jeśli masz dowolny obiekt, który można modyfikować.
Mike Graham
1
W razie potrzeby można przyspieszyć, że źle w pętli, może to być czas, aby użyć Cython, splot, lub podobny ...
james.haggerty
1
@JohnLaRooy myślę, że wymieniane xi y. Nie powinno tak być[[copy.deepcopy(foo) for y in range(10)] for x in range(10)]
użytkownik3085931,
1
@Nils [foo]*10nie tworzy 10 różnych obiektów - ale łatwo przeoczyć różnicy w przypadku, gdy foo jest niezmienne, jak u intlub str.
John La Rooy
137

Nie używaj [[v]*n]*n, to pułapka!

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

ale

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

działa świetnie.

Jason CHAN
źródło
26
tak, też wpadłem w tę pułapkę. To dlatego, że *kopiuje addressobiekt (listę).
chinuy
1
Głosowałem, ponieważ mnie to wciągnęło. Aby być bardziej precyzyjne, [[0] * col for _ in range(row)].
Abhijit Sarkar,
62

Aby zainicjować tablicę dwuwymiarową w Pythonie:

a = [[0 for x in range(columns)] for y in range(rows)]
Vipul
źródło
4
Aby zainicjować wszystkie wartości na 0, wystarczy użyć 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)]
Ignacio Vazquez-Abrams
źródło
1
xrange () został usunięty w
python3.5
dlaczego to nie działa: [0 * col] * wiersz. Kiedy modyfikuję jakiś element, replikuje się w innych miejscach. Ale nie rozumiem dlaczego?
Code Muncher
Ponieważ robi to dokładnie to samo, co kod w pytaniu.
Ignacio Vazquez-Abrams
2
@codemuncher Powodem, dla którego [[0] * col] * rownie robisz tego, co chcesz, jest to, że po zainicjowaniu listy 2D w ten sposób Python nie utworzy odrębnych kopii każdego wiersza. Zamiast tego zainicjuje zewnętrzną listę ze wskaźnikami do tej samej kopii [0]*col. Wszelkie zmiany dokonane w jednym z wierszy zostaną odzwierciedlone w pozostałych wierszach, ponieważ wszystkie one faktycznie wskazują te same dane w pamięci.
Addie
To tylko myśl, ale czy te wszystkie listy nie są dobre do dołączenia? To znaczy. jeśli chcę pustą listę 2D o wymiarze 3 * 6 i chcę dołączyć do indeksu [0] [0], [1] [0], [2] [0] i tak dalej, aby wypełnić wszystkie 18 elementów, żaden z te odpowiedzi zadziałają, prawda?
mLstudent33
22

Zwykle, gdy potrzebujesz tablic wielowymiarowych, nie potrzebujesz listy list, a raczej tablicy numpy lub ewentualnie dyktanda.

Na przykład za pomocą numpy zrobiłbyś coś takiego

import numpy
a = numpy.empty((10, 10))
a.fill(foo)
Mike Graham
źródło
2
Chociaż numpyjest świetny, myślę, że dla początkującego może to być trochę przesada.
Esteban Küber,
3
numpy zapewnia wielowymiarowy typ tablicy. Zbudowanie dobrej wielowymiarowej tablicy z list jest możliwe, ale mniej przydatne i trudniejsze dla początkującego niż używanie numpy. Listy zagnieżdżone świetnie nadają się do niektórych aplikacji, ale zwykle nie najlepiej jest, jeśli ktoś chce tablicy 2d.
Mike Graham,
1
po kilku latach od czasu do czasu robienia poważnych aplikacji w języku Python, dziwactwa standardowych tablic pytona wydają się uzasadniać kontynuację numpy. +1
javadba
12

Możesz to zrobić:

[[element] * numcols] * numrows

Na przykład:

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

Ale ma to niepożądany efekt uboczny:

>>> 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
źródło
11
Z mojego doświadczenia wynika, że ​​ten „niepożądany” efekt jest często źródłem bardzo złych błędów logicznych. Moim zdaniem tego podejścia należy unikać, zamiast tego odpowiedź @ Vipul jest znacznie lepsza.
Alan Turing
takie podejście działa dobrze, dlaczego w komentarzach niektórzy mówią, że jest tak źle?
Bravo,
1
Ze względu na niepożądany efekt uboczny nie można tak naprawdę traktować go jak matrycy. Jeśli nie musisz zmieniać zawartości, wszystko będzie w porządku.
hithwen
9
twod_list = [[foo for _ in range(m)] for _ in range(n)]

dla n oznacza liczbę wierszy, a m jest liczbą kolumn, a foo jest wartością.

Moustafa Saleh
źródło
8

Jeśli jest to tablica słabo zaludniona, lepiej byłoby użyć słownika z krotką:

dict = {}
key = (a,b)
dict[key] = value
...
btk
źródło
5
t = [ [0]*10 for i in [0]*10]

dla każdego elementu [0]*10zostanie utworzony nowy ..

użytkownik9269722
źródło
4

Niepoprawne podejście: [[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

Dzięki takiemu podejściu python nie pozwala na tworzenie innej przestrzeni adresowej dla zewnętrznych kolumn i doprowadzi do innego niewłaściwego zachowania niż się spodziewasz.

Prawidłowe podejście, ale z wyjątkiem:

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

Jest to dobre podejście, ale istnieje wyjątek, jeśli ustawisz wartość domyślną na 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

Więc ustaw poprawnie wartość domyślną, stosując to podejście.

Absolutnie poprawne:

Postępuj zgodnie z odpowiedzią Mike'a dotyczącą podwójnej pętli .

patilnityna
źródło
3
Matrix={}
for i in range(0,3):
  for j in range(0,3):
    Matrix[i,j] = raw_input("Enter the matrix:")
Sparsh
źródło
1
Chociaż ten kod może odpowiedzieć na pytanie, zapewnienie dodatkowego kontekstu dotyczącego tego, dlaczego i / lub jak ten kod odpowiada na pytanie, poprawia jego długoterminową wartość.
Ajean
3

Aby zainicjować tablicę dwuwymiarową, użyj: arr = [[]*m for i in range(n)]

faktycznie arr = [[]*m]*nstworzy tablicę 2D, w której wszystkie n tablic wskaże tę samą tablicę, więc każda zmiana wartości w dowolnym elemencie zostanie odzwierciedlona na wszystkich n listach

więcej dalszych wyjaśnień na stronie: https://www.geeksforgeeks.org/python-using-2d-arrays-lists-the-right-way/

Abhimanyu
źródło
3

użyj najprostszej myśli, aby to stworzyć.

wtod_list = []

i dodaj rozmiar:

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

lub jeśli chcemy najpierw zadeklarować rozmiar. używamy tylko:

   wtod_list = [[0 for x in xrange(10)] for x in xrange(10)]
indi60
źródło
1

Jak zauważyli @Arnab i @Mike, tablica nie jest listą. Kilka różnic to 1) tablice mają ustalony rozmiar podczas inicjalizacji 2) tablice zwykle obsługują mniejsze operacje niż lista.

Może w większości przypadków przesada, ale tutaj jest podstawowa implementacja tablicy 2d, która wykorzystuje sprzętową implementację tablicy przy użyciu ctypów python (bibliotek 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
źródło
1

Ważną rzeczą, którą zrozumiałem, jest: Podczas inicjowania tablicy (w dowolnym wymiarze) powinniśmy nadać domyślną wartość wszystkim pozycjom tablicy. Następnie kończy się tylko inicjalizacja. Następnie możemy zmienić lub otrzymać nowe wartości do dowolnej pozycji tablicy. Poniższy kod działał dla mnie idealnie

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
źródło
1

Jeśli używasz numpy , możesz łatwo tworzyć tablice 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
źródło
1
row=5
col=5
[[x]*col for x in [b for b in range(row)]]

Powyższe daje macierz 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]]

Korzysta ze zrozumienia listy zagnieżdżonej. Podział jak poniżej:

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

[x] * col -> końcowe wyrażenie, które jest oceniane
dla x w -> x będzie wartością podaną przez iterator
[b dla bw zakresie (wiersz)]] -> Iterator.

[b dla bw przedziale (rzędzie)]] spowoduje to ocenę do [0,1,2,3,4], ponieważ wiersz = 5,
więc teraz upraszcza się

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

Będzie to oceniać na [[0] * 5 dla x w [0,1,2,3,4]] -> przy x = 0 1. iteracja
[[1] * 5 dla x w [0,1,2, 3,4]] -> przy x = 1 2. iteracja
[[2] * 5 dla x w [0,1,2,3,4]] -> przy x = 2 3. iteracja
[[3] * 5 dla x w [0,1,2,3,4]] -> przy x = 3 4. iteracja
[[4] * 5 dla x w [0,1,2,3,4]] -> z x = 4 5. iteracja

Satya
źródło
0

To najlepsze, jakie znalazłem do nauczania nowych programistów i bez korzystania z dodatkowych bibliotek. Chciałbym jednak coś lepszego.

def initialize_twodlist(value):
    list=[]
    for row in range(10):
        list.append([value]*10)
    return list
Paul Vincent Craven
źródło
0

Oto łatwiejszy sposób:

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

Do zainicjowania wszystkich komórek dowolną wartością „x” użyj:

twoD = np.array([[x]*m]*n
użytkownik3650331
źródło
0

Często używam tego podejścia do inicjowania tablicy dwuwymiarowej

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


źródło
0

Ogólny wzór dodawania wymiarów można narysować z tej serii:

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
źródło
Witamy w SO. To pytanie ma już zdecydowanie głosowaną odpowiedź. Na pierwszy rzut oka ten post nie odpowiada na pytanie. Aby uzyskać wskazówki, zobacz stackoverflow.com/help/how-to-answer .
Nick
0

Możesz spróbować tego [[0] * 10] * 10. Zwróci tablicę 2d 10 wierszy i 10 kolumn o wartości 0 dla każdej komórki.

ishant
źródło
To jest w zasadzie taka sama odpowiedź jak stackoverflow.com/a/25601284/2413201 ...
Armali
2
To tworzy tablicę 10 wskaźników do tego samego wiersza. Jeśli to zrobisz a = [[0]*10]*10, a następnie a[0][0] = 1widać, że pierwszy element w każdym wierszu teraz równa 1
andnik
0

lst = [[0] * m dla i w zakresie (n)]

zainicjuj całą macierz n = wiersze im = kolumny

HRITIK RAJENDRA AKOLKAR
źródło
Czy możesz sformatować kod jako kod? Byłby o wiele bardziej czytelny.
Thomas
0

Innym sposobem jest użycie słownika do przechowywania tablicy dwuwymiarowej.

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

Może to po prostu przechowywać dowolne wartości 1D, 2D i aby zainicjować tę wartość 0lub dowolną inną wartość int, użyj kolekcji .

import collections
twoD = collections.defaultdict(int)
print(twoD[0,0]) # ==> prints 0
twoD[1,1] = 1
print(twoD[1,1]) # ==> prints 1
Tej91
źródło
0

Kod:

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 musi być niezmienny.

Abhishek Bhatia
źródło
-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
źródło
4
Dodaj tekst opisujący działanie kodu.
whackamadoodle3000,
1
Zwykle lepiej jest wyjaśnić rozwiązanie zamiast po prostu opublikować kilka wierszy anonimowego kodu. Możesz przeczytać Jak napisać dobrą odpowiedź , a także wyjaśnienie odpowiedzi całkowicie opartych na kodzie .
Massimiliano Kraus