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?

Masoud Abasian
źródło
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.

Manny D.
źródło
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.

senderle
źródło
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]]
Andrew Clark
źródło
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)]
mripard
źródło
@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ść.

enobayram
źródło
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)]
jagoda
źródło
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

[[], [], []]
fabiański
źródło
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
utdemir
źródło
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.

nieznany błąd
źródło
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)
Manohar Reddy Poreddy
źródło
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.

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

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

Michał
źródło
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
użytkownik110954
źródło
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)
Namrata Tolani
źródło
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]

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

alessadnro
źródło
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],
   ...
Mohammad Mahdi KouchakYazdi
źródło
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.

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

Saurabh Chandra Patel
źródło
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]]
Nagendra Nigade
źródło
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

和風 信使
źródło
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)] 
Ostra Sharma
źródło
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], []]
Meraj al Maksud
źródło
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())))
Ankit Sharma
źródło
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]]
Vlad Bezden
źródło
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.

Chandra Shekhar
źródło