Jak zdefiniować tablicę dwuwymiarową w Pythonie


723

Chcę zdefiniować tablicę dwuwymiarową bez zainicjowanej długości w następujący sposób:

Matrix = [][]

ale to nie działa...

Wypróbowałem poniższy kod, ale jest również nieprawidłowy:

Matrix = [5][5]

Błąd:

Traceback ...

IndexError: list index out of range

Jaki jest mój błąd?


14
Nie definiuje się tablic ani niczego innego. Możesz jednak tworzyć wielowymiarowe sekwencje, jak pokazują odpowiedzi tutaj. Pamiętaj, że zmienne w Pythonie są bez typu, ale wartości są mocno wpisane.
SingleNegationElimination

1
Jestem zmieszany. Pochodzi z innych języków: jest to różnica między tablicą 1D zawierającą tablice 1D a tablicą 2D. A AFAIK nie ma możliwości posiadania wielowymiarowej tablicy (lub listy) w pythonie. Należy powiedzieć tutaj ...
Dirk Reichel

1
Zobacz także FAQ Python3 na temat tworzenia listy wielowymiarowej?
Kevin W Matthews,

Odpowiedzi:


1008

Technicznie próbujesz zaindeksować niezainicjowaną tablicę. Przed dodaniem elementów musisz najpierw zainicjować zewnętrzną listę za pomocą list; Python nazywa to „rozumieniem listy”.

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

Możesz teraz dodawać elementy do listy:

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

Zauważ, że macierz ma „y” adres główny, innymi słowy, „indeks y” znajduje się przed „indeksem x”.

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

Chociaż możesz nazwać je według własnego uznania, patrzę na to w ten sposób, aby uniknąć nieporozumień, które mogłyby powstać podczas indeksowania, jeśli użyjesz „x” zarówno dla wewnętrznej, jak i zewnętrznej listy, i chcesz macierzy nie kwadratowej.


219
[[0 dla xw zasięgu (cols_count)] dla x w zakresie (row_count)]
songhir

3
Nieparzysta edycja przez ademar111190. W Pythonie 3 nie ma Xrange, ale jeśli musisz użyć Python 2, to Xrange jest poprawną funkcją do użycia, jeśli nie chcesz niepotrzebnie tworzyć obiektów.
Dave

4
@dave Jeśli nie potrzebujesz go wypełnionego zerem, możesz użyć go rangedo bezpośredniego utworzenia wewnętrznych list:[range(5) for x in range(5)]
alanjds

2
@alanjds - to prawda, ale wciąż tworzysz potencjalnie wiele niepotrzebnych odwołań do obiektów w Pythonie 2 dla zewnętrznej iteracji (spróbuj tego z BARDZO dużym zakresem). Ponadto, inicjalizacja do pewnej wartości jest prawie zawsze tym, czego chcesz - i jest to częściej niż 0. zakres daje iterowalną kolekcję - xrange zwraca generator. Chodziło mi o to, że ademar „poprawił” coś, co w rzeczywistości było ogólnie bardziej poprawne i skuteczne niż jego poprawka.
Dave,

10
@ 6packkid [0] * wczęść jest ładna, ale [[0] * w] * h]spowoduje nieoczekiwane zachowanie. Spróbuj mat = [[0] * 3] * 3; mat[0][1] = 10; print(mat == [[0, 10, 0], [0, 10, 0], [0, 10, 0]])i mat = [[0] * 3 for i in range(3)]; mat[0][1] = 10; print(mat == [[0, 10, 0], [0, 0, 0], [0, 0, 0]]).
senderle

407

Jeśli naprawdę chcesz matrycę, lepiej skorzystać z niej numpy. Operacje na numpymacierzach najczęściej wykorzystują typ macierzy o dwóch wymiarach. Istnieje wiele sposobów tworzenia nowej tablicy; jedną z najbardziej przydatnych jest zerosfunkcja, która pobiera parametr kształtu i zwraca tablicę danego kształtu, z wartościami zainicjowanymi na 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.]])

Oto kilka innych sposobów tworzenia dwuwymiarowych tablic i macierzy (z wyjściem usuniętym ze względu na zwartość):

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

numpyzapewnia również matrixtyp, ale nie jest już zalecany do jakiegokolwiek użytku i może zostać usunięty numpyw przyszłości.


78
Kiedykolwiek chcesz macierzy, chcesz użyć numpy. Ta odpowiedź powinna być pierwsza.
Pat B

2
Fakt, że pytanie używa angielskiego słowa „matryca”, nie oznacza, że ​​powinni go użyć np.matrixdo jego przedstawienia. Właściwym sposobem przedstawienia macierzy w liczbach liczbowych jest użycie znaku array.
użytkownik2357112 obsługuje Monikę

@ user2357112, i jak widać, większość przykładów wymienionych powyżej generuje wyniki arrayzamiast matryc. Chociaż nie zawsze jest to zalecane, istnieją uzasadnione powody używania matrix- kontekst ma znaczenie.
senderle

1
@senderle, czy możesz rozwinąć listę powodów, dla których warto skorzystać matrix? Od czasu @wprowadzenia operatora wydaje się, że istnieje jeden mniejszy powód od napisania tego postu.
jpp

1
@jpp, jak wcześniej napisano, ludzie pochodzący z Matlaba mogą się przydać. Ale numpydokumenty wskazują teraz, że klasa może być przestarzała i usunięta w przyszłości, więc wyjąłem ją z odpowiedzi.
senderle

337

Oto krótsza notacja dotycząca inicjowania listy list:

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

Niestety, skrócenie tego do czegoś takiego 5*[5*[0]]nie działa, ponieważ kończy się to 5 kopiami tej samej listy, więc po zmodyfikowaniu jednej z nich wszystkie się zmieniają, na przykład:

>>> 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
Czy możesz wyjaśnić logikę niepowodzenia „skracania”? Dlaczego w tym przypadku Python generuje kopie tej samej listy i tablicę różnych komórek w przypadku [0]*5?
mike622867

12
Powyższe komentarze nie są do końca prawdziwe: [0] * 5 nadal tworzy sekwencję z 5-krotnym odniesieniem do tego samego obiektu reprezentującego liczbę 0. Ale nigdy tego nie zauważysz, ponieważ 0 jest niezmienne (powiedziałbym, że 0 zachowuje się jak wartość - lub możesz myśleć o tym jako o prymitywnym typie danych - ponieważ jest niezmienny, więc nigdy nie masz problemów z odniesieniami do tego samego obiektu zamiast kopii.)
dreua

4
więcej python: [[0]*5 for _ in range(5)]z anonimowym licznikiem pętli, z którego nie korzystasz
Jean-François Fabre

Fajnie, że wskazałeś problem płytkiej kopii w drugim przykładzie.
whatacold

dzięki @dreua, byłem naprawdę zdezorientowany, jak [0]*5działa dobrze. Teraz rozumiem, dlaczego też [{0}]*8byłby zły pomysł.
kuku

110

Jeśli chcesz utworzyć pustą macierz, poprawna składnia to

matrix = [[]]

A jeśli chcesz wygenerować macierz o rozmiarze 5 wypełnioną 0,

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

@KorayTugay Ponieważ macierz jest reprezentowana za pomocą list (-ów) Pythona (wierszy) zagnieżdżonych na innej liście (kolumnach).
elig

2
W przypadku Python-3 użyj funkcji zakresu zamiast xrange func
Rakesh Chaudhari

76

Jeśli wszystko, czego potrzebujesz, to dwuwymiarowy pojemnik do przechowywania niektórych elementów, możesz zamiast tego wygodnie użyć słownika:

Matrix = {}

Następnie możesz zrobić:

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

Działa 1,2to, ponieważ jest krotką i używasz go jako klucza do indeksowania słownika. Wynik jest podobny do głupiej rzadkiej matrycy.

Jak wskazują osa i Josap Valls, możesz również użyć, Matrix = collections.defaultdict(lambda:0)aby brakujące elementy miały domyślną wartość 0.

Vatsal wskazuje ponadto, że ta metoda prawdopodobnie nie jest bardzo wydajna w przypadku dużych matryc i powinna być stosowana tylko w częściach kodu, które nie mają krytycznego wpływu na wydajność.


2
Następnie możesz również zrobić import collections; Matrix = collections.defaultdict(float), aby zastąpić niezainicjowane elementy zerami.
osa

2
Nie uzyskałbym dostępu do dykta dla krotki (1,2), ponieważ klucz ma w najgorszym przypadku złożoność O (n). Wewnętrznie haszuje krotki. Podczas gdy użycie tablicy 2D dałoby O (1) czas na złożoność dostępu do dostępu do indeksu [1,2]. Dlatego użycie dict do tego nie powinno być dobrym wyborem.
Vatsal

@Vatsal wiki.python.org/moin/TimeComplexity mówi, że średni przypadek to O (1), ale masz rację co do najgorszego przypadku. W każdym razie, chyba że mówisz o wielu przedmiotach, nie przejmujesz się tą różnicą. W rzeczywistości martwiłbym się bardziej pamięcią niż czasem dostępu.
enobayram

Zawsze też staramy się unikać używania nagrań, dopóki ogólna złożoność algorytmu nie będzie równa lub większa niż O (n ^ 2). Gdy razy „n” dostęp do O (n) dałby złożoność O (n ^ 2).
Vatsal

@enobayram, przepraszam, ale nie zgadzam się. Analiza asymptotyczna zawsze da O (n ^ 2), jeśli w najgorszym przypadku dostęp O (n) jest wykonywany „n” razy. Gdzie według amortyzacji analiza może dać mniejszy związek. I istnieje ogromna różnica między zamortyzowanym a średnim przypadkiem ... prosimy o
zapoznanie się z

42

W Pythonie będziesz tworzyć listę list. Nie musisz wcześniej deklarować wymiarów, ale możesz. Na przykład:

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

Teraz macierz [0] [0] == 2 i macierz [1] [0] == 3. Możesz także użyć składni zrozumienia listy. W tym przykładzie użyto go dwa razy, aby utworzyć „dwuwymiarową listę”:

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
extendbyłoby również pomocne w pierwszym przypadku: jeśli zaczniesz od m = [[]], możesz dodać do wewnętrznej listy (rozszerzyć wiersz) za pomocą m[0].extend([1,2])i dodać do listy zewnętrznej (dodać nowy wiersz) za pomocą m.append([3,4]), te operacje pozostawiają cię [[1, 2], [3, 4]].
askewchan

22

Przyjęta odpowiedź jest dobra i poprawna, ale zajęło mi trochę czasu, aby zrozumieć, że mogę jej również użyć do stworzenia całkowicie pustej tablicy.

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

prowadzi do

[[], [], []]

22

Powinieneś zrobić listę list, a najlepszym sposobem jest użycie zagnieżdżonych wyrażeń:

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

Na twoim [5][5]przykładzie tworzysz listę z liczbą całkowitą „5” w środku i próbujesz uzyskać dostęp do jej piątego elementu, co naturalnie podnosi błąd IndexError, ponieważ nie ma piątego elementu:

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

W rzeczywistości sekwencje dla indeksu_wiersza („i”) i indeksu_kolumny („j”) są następujące: „>>> matrix = [[0 dla indeksu_kolumny w zakresie (5)] dla indeksu_wierszy w zakresie (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)

Skąd taki długi kod, o który też Pythonpytasz?

Dawno temu, kiedy nie czułem się dobrze w Pythonie, zobaczyłem odpowiedzi w jednej linii do pisania matrycy 2D i powiedziałem sobie, że nie zamierzam ponownie używać matrycy 2D w Pythonie. (Te pojedyncze wiersze były dość przerażające i nie dawały mi żadnych informacji o tym, co robił Python. Zauważ też, że nie znam tych skrótów.)

Tak czy inaczej, oto kod dla początkującego, który pochodzi z C, CPP i Java

Uwaga dla miłośników i ekspertów Python: Proszę nie głosować, ponieważ napisałem szczegółowy kod.


13

Przepisanie do łatwego czytania:

# 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

Posługiwać się:

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

* 5 dla pierwszego wymiaru działa, ponieważ na tym poziomie dane są niezmienne.


5
Prawdopodobnie napisałbym to jakomatrix = [[0]*cols for _ in range(rows)]
Shital Shah

12

Aby zadeklarować macierz zer (jedynek):

numpy.zeros((x, y))

na przykład

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

lub numpy.ones ((x, y)) np

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

Możliwe są nawet trzy wymiary. ( http://www.astro.ufl.edu/~warner/prog/python.html patrz -> Tablice wielowymiarowe)


12

W ten sposób zwykle tworzę tablice 2D w Pythonie.

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

Uważam tę składnię za łatwą do zapamiętania w porównaniu do używania dwóch pętli for w zrozumieniu listy.


11

Korzystam z pierwszego skryptu w języku Python i byłem trochę zdezorientowany przykładem macierzy kwadratowej, więc mam nadzieję, że poniższy przykład pomoże ci zaoszczędzić trochę czasu:

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

po to aby

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

10

Za pomocą NumPy możesz zainicjować pustą macierz w następujący sposób:

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

A później dodaj takie dane:

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

jakie byłyby zalety i wady korzystania z numpy zamiast „rozumienia listy”?
Revolucion for Monica

7

Czytam pliki rozdzielone przecinkami, takie jak to:

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

Lista „data” to lista list z danymi indeksu [wiersz] [col]


7

Jeśli chcesz myśleć o tym jak o macierzy 2D zamiast zmuszać się do myślenia na podstawie listy list (moim zdaniem bardziej naturalnie), możesz wykonać następujące czynności:

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

Wynikiem jest lista (a nie tablica NumPy), a poszczególne pozycje można nadpisać liczbami, ciągami znaków i innymi.


numpy.matrixrównoważne numpy.zeroszerom bez listy?
Revolucion for Monica

6

Do tego służy słownik !

matrix = {}

Możesz zdefiniować klucze i wartości na dwa sposoby:

matrix[0,0] = value

lub

matrix = { (0,0)  : value }

Wynik:

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

6

Posługiwać się:

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

Myślę, że NumPy jest właściwą drogą. Powyższe jest ogólne, jeśli nie chcesz używać NumPy.


Podoba mi się ta próba zrobienia czegoś prostego z waniliowym Pythonem bez konieczności używania numpy.
Rick Henderson

4

za pomocą listy:

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

za pomocą dict: możesz również przechowywać te informacje w tabeli skrótów, aby szybko wyszukiwać jak

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

macierz [1] daje wynik w czasie O (1)

* nb : musisz poradzić sobie z kolizją w tabeli skrótów


4

Jeśli nie masz informacji o rozmiarze przed rozpoczęciem, utwórz dwie jednowymiarowe listy.

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

Zapisz cały wiersz na 1. liście. Po zakończeniu dołącz listę 1 do listy 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

Wynik:

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

Uważaj na to krótkie wyrażenie, zobacz pełne wyjaśnienie w odpowiedzi na @ FJ


19
Bądź ostrożny w ten sposób, ponieważ Matrix[0], Matrix[1], ..., Matrix[4]wszystkie wskazują na tę samą tablicę, więc później Matrix[0][0] = 3możesz się spodziewać Matrix[0][0] == Matrix[1][0] == ... == Matrix[4][0] == 3.
gongzhitaao

1
Dzięki gongzhitaao za komentarz. Gdybym przeczytał to wcześniej, zaoszczędziłoby mi to co najmniej pół godziny. Posiadanie matrycy, w której każdy wiersz wskazuje to samo miejsce w pamięci, nie wydaje się bardzo przydatne, a jeśli nie jesteś świadomy tego, co robisz to nawet niebezpieczne! Jestem prawie pewien, że NIE tego chce Masoud Abasian, który zadał to pytanie.
Adrian

7
Powinieneś usunąć tę odpowiedź, ponieważ jest to nieprawidłowa odpowiedź. Początkujący mogą być zdezorientowani.
cxxl,

2
Jakiej odpowiedzi masz na myśli? Nie widzę użytkownika o nazwie „FJ” (nawet w usuniętych odpowiedziach).
Peter Mortensen

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

Będzie szybszy niż:

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

2
Duplikat odpowiedzi na jedną już odpowiedzią poniżej. Również [[0]*(L) for i in range(W)]powinny być [[0]*(L) for _ in range(W)]ponieważ inie jest stosowany wszędzie
Ayush Vatsyayan

2

Możesz utworzyć pustą dwuwymiarową listę, zagnieżdżając dwa lub więcej nawiasów kwadratowych lub trzeciego nawiasu ( []oddzielonych przecinkiem) za pomocą nawiasów kwadratowych, tak jak poniżej:

Matrix = [[], []]

Załóżmy teraz, że chcesz dodać 1, Matrix[0][0]a następnie wpisać:

Matrix[0].append(1)

Teraz wpisz Matrix i naciśnij Enter. Dane wyjściowe będą:

[[1], []]

1

Spróbuj tego:

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

1

Jeśli potrzebujesz macierzy ze wstępnie zdefiniowanymi liczbami, możesz użyć następującego kodu:

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

Oto fragment kodu służący do tworzenia macierzy w pythonie:

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

Proszę zasugerować, jeśli coś przeoczyłem.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.