Як визначити двовимірний масив у Python


723

Я хочу визначити двовимірний масив без ініціалізованої довжини, як це:

Matrix = [][]

але це не працює ...

Я спробував код нижче, але він також неправильний:

Matrix = [5][5]

Помилка:

Traceback ...

IndexError: list index out of range

Яка моя помилка?


14
Одне не визначає масиви чи будь-яку іншу річ. Однак можна створити багатовимірні послідовності, як показують відповіді тут. Пам'ятайте, що змінні python не типізовані, але значення сильно набрані.
SingleNegationElimination

1
Я збентежений. Походить з інших мов: це різниця між 1D-масивом, що містить 1D-масиви, і 2D-масивом. А в AFAIK немає можливості мати багатовимірний масив (або список) у python. Слід сказати тут ...
Дірк Райхель

1
Див. Також поширені запитання Python3 у розділі Як створити багатовимірний список?
Kevin W Matthews

Відповіді:


1008

Ви технічно намагаєтесь індексувати неініціалізований масив. Ви повинні спочатку ініціалізувати зовнішній список зі списками, перш ніж додавати елементи; Python називає це "розумінням списку".

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

Тепер ви можете додати елементи до списку:

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

Зауважте, що матриця є "y" основною адресою, іншими словами, "y індекс" надходить до "x індексу".

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

Хоча ви можете назвати їх за своїм бажанням, я розглядаю це таким чином, щоб уникнути певної плутанини, яка може виникнути при індексації, якщо ви використовуєте "x" як для внутрішнього, так і для зовнішнього списків, і хочете неквадратичну Матрицю.


219
[[0 для x у діапазоні (cols_count)] для x у діапазоні (rows_count)]
songhir

3
Незвичайна редакція від ademar111190. У Python 3 немає xrange, але якщо ви повинні використовувати Python 2, то xrange - це правильна функція, яка використовується, якщо ви не хочете створювати об'єкти.
Дейв

4
@dave Якщо вам цього не потрібно заповнювати нулями, можна використовувати rangeдля створення внутрішніх списків безпосередньо:[range(5) for x in range(5)]
alanjds

2
@alanjds - це правда, але ви все ще створюєте потенційно багато непотрібних посилань на об'єкти в Python 2 для зовнішньої ітерації (спробуйте це ДУЖЕ великий діапазон). Крім того, ініціалізація деякого значення майже завжди є тим, що ви хочете - і це частіше ніж 0. Діапазон дає ітерабельну колекцію - xrange повертає генератор. Моя думка полягала в тому, що адемар "виправив" щось, що насправді було більш загальним і ефективним, ніж його виправлення.
Дейв

10
@ 6packkid [0] * wчастина приємна, але [[0] * w] * h]породжує несподівану поведінку. Спробуйте mat = [[0] * 3] * 3; mat[0][1] = 10; print(mat == [[0, 10, 0], [0, 10, 0], [0, 10, 0]])і 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

Якщо ви дійсно хочете матриці, можливо, вам буде краще використовувати numpy. Матричні операції numpyнайчастіше використовують тип масиву з двома вимірами. Є багато способів створити новий масив; однією з найбільш корисних є zerosфункція, яка приймає параметр фігури і повертає масив заданої форми зі значеннями, ініціалізованими до нуля:

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

Ось кілька інших способів створення 2-d масивів та матриць (з вилученим результатом для компактності):

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

numpyнадає matrixтип, але він більше не рекомендується для будь-якого використання і може бути видалений з numpyмайбутнього.


78
Всякий раз, коли ви хочете матриць, ви хочете використовувати numpy. Ця відповідь повинна бути першою.
Пат Б

2
Те, що в питанні використовується англійське слово "матриця", не означає, що вони повинні використовувати його np.matrixдля представлення. Правильний спосіб представити матрицю в numpy - це за допомогою an array.
user2357112 підтримує Monica

@ user2357112, І як ви бачите, більшість прикладів, перелічених вище, виводять arrays замість матриць. Хоча це не завжди рекомендується, існують законні причини використання matrixконтексту.
senderle

1
@senderle, Чи можете ви розширити причини використання matrix? З моменту @введення оператора, мабуть, є ще одна причина, оскільки ця публікація була написана.
jpp

1
@jpp, як повідомлялося раніше, люди, які походять з matlab, можуть вважати його корисним. Але numpyдокументи зараз вказують, що клас може бути застарілим і видалений у майбутньому, тому я його вийняв з відповіді.
відправник

337

Ось коротше позначення для ініціалізації списку:

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

На жаль, скорочення цього до чогось подібного 5*[5*[0]]насправді не працює, оскільки ви отримуєте 5 копій того ж списку, тож коли ви змінюєте одну з них, вони все змінюються, наприклад:

>>> 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
Чи можете ви пояснити логіку, що стоїть за невдачею "скорочення"? Чому python виводить копії одного списку в цьому випадку та масив різних комірок у випадку [0]*5?
mike622867

12
Наведені вище коментарі не зовсім вірні: [0] * 5 все ще створює послідовність із 5-кратним посиланням на той самий Об'єкт, що представляє число 0. Але цього ви ніколи не помітите, оскільки 0 незмінний (я б сказав, 0 поводиться як значення - або ви можете подумати про це як про примітивний тип даних - тому що він незмінний, тому ви ніколи не матимете проблем із посиланнями на той самий об’єкт, а не з копіями.)
dreua

4
ще пітонічний: [[0]*5 for _ in range(5)]з анонімним лічильником циклу, який ви не використовуєте
Жан-Франсуа Фабре

Приємно, що ви вказуєте на проблему дрібної копії у другому прикладі.
whatacold

дякую @dreua, я дуже розгубився, як це [0]*5працює чудово. Тепер я розумію, чому також [{0}]*8було б поганою ідеєю.
куку

110

Якщо ви хочете створити порожню матрицю, правильним є синтаксис

matrix = [[]]

І якщо ви хочете створити матрицю розміру 5, заповнену 0,

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

@KorayTugay Оскільки матриця представлена ​​за допомогою списків Python (рядків), вкладених всередині іншого списку (стовпців).
elig

2
Для Python-3 використовуйте функцію діапазону замість xrange func
Ракеш Чаудхарі,

76

Якщо все, що вам потрібно, - це двомірний контейнер для вміщення деяких елементів, ви можете зручно використовувати словник:

Matrix = {}

Тоді ви можете зробити:

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

Це працює тому, що 1,2є кортежем, і ви використовуєте його як ключ для індексації словника. Результат схожий на тупу розріджену матрицю.

Як вказують osa та Josap Valls, ви також можете використовувати Matrix = collections.defaultdict(lambda:0)так, щоб відсутні елементи були за замовчуванням 0.

Далі Ватсал зазначає, що цей метод, мабуть, не дуже ефективний для великих матриць, і його слід застосовувати лише в критичних для коду частинах коду.


2
Тоді ви також можете зробити import collections; Matrix = collections.defaultdict(float)підстановку нулів на неініціалізовані елементи.
оса

2
Не маючи доступу до диктату для кортежу (1,2) як ключа, найгірший складний випадок становить O (n). Внутрішньо він би хешував кортежі. Тоді як використання 2D-масиву дасть O (1) часову складність доступу до індексу [1,2]. Тож використання dict для цього не повинно бути хорошим вибором.
Ватсал

@Vatsal wiki.python.org/moin/TimeComplexity каже, що середній випадок - це O (1), але ви маєте рацію щодо найгіршого випадку. У будь-якому разі, якщо ви не говорите про ДЛЯ ПУНКТІВ, ви б не переймалися цією різницею. Власне кажучи, я б більше хвилювався за пам'ять, ніж про час доступу.
енобайрам

Також ми завжди намагаємось уникати використання диктів, поки загальна складність алгоритму не дорівнює або перевищує O (n ^ 2). Як "n" разів O (n) доступ давав би складність O (n ^ 2).
Ватсал

@enobayram, Вибачте, але я не згоден. Асимптотичний аналіз завжди дасть O (n ^ 2), якщо найгірший випадок доступу O (n) робиться "n" разів. Де амортизований аналіз може дати меншу межу. І існує велика різниця між амортизованим та середнім випадком ... будь ласка, зверніться до того, щоб робити будь-які припущення та розпливчасті коментарі
Vatsal

42

У Python ви будете створювати список списків. Не потрібно оголошувати розміри достроково, але ви можете. Наприклад:

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

Тепер матриця [0] [0] == 2 та матриця [1] [0] == 3. Можна також використовувати синтаксис розуміння списку. Цей приклад використовує його двічі для створення "двовимірного списку":

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
extendбуло б також корисно в першому випадку: Якщо ви почнете з m = [[]], тоді ви можете додати до внутрішнього списку (розширити рядок) за допомогою m[0].extend([1,2])та додати до зовнішнього списку (додати новий рядок) з m.append([3,4]), ці операції залишать вас [[1, 2], [3, 4]].
askewchan

22

Прийнята відповідь хороша і правильна, але мені знадобилося певний час, щоб зрозуміти, що я також міг би використати її для створення абсолютно порожнього масиву.

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

призводить до

[[], [], []]

22

Вам слід скласти список списків, і найкращим способом є використання вкладених розумінь:

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

У вашому [5][5]прикладі ви створюєте список з цілим числом "5" всередині і намагаєтеся отримати доступ до його 5-го елемента, і це, природно, піднімає IndexError, оскільки немає 5-го елемента:

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

Насправді послідовність для row_index ('i') та column_index ('j') така: '>>> matrix = [[0 для column_index у діапазоні (5)] для row_index у діапазоні (5)]'
Анірудда Кальбургі

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)

Чому такий довгий код, що теж у Pythonвас запитують?

Довго назад, коли мені було не комфортно з Python, я побачив відповіді на один рядок для написання 2D-матриці і сказав собі, що більше не збираюся використовувати 2-D матрицю в Python. (Ці єдині рядки були досить страшними, і це не дало мені ніякої інформації про те, що робив Python. Також зауважте, що я не знаю про ці скорочення.)

У будь-якому випадку, ось код для початківця, який походить з C, CPP та Java-фону

Примітка любителям та експертам Python: Будь ласка, не відмовляйтесь від голосування лише тому, що я написав детальний код.


13

Перезапис для легкого читання:

# 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

Використання:

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

* 5 для першого виміру працює, оскільки на цьому рівні дані незмінні.


5
Я б, мабуть, написав це якmatrix = [[0]*cols for _ in range(rows)]
Shital Shah

12

Для оголошення матриці нулів (одиниць):

numpy.zeros((x, y))

напр

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

або numpy.ones ((x, y)), наприклад

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

Можливі навіть три виміри. ( http://www.astro.ufl.edu/~warner/prog/python.html див. -> Багатовимірні масиви)


12

Так я зазвичай створюю 2D масиви в python.

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

Мені здається, що цей синтаксис легко запам'ятовується порівняно з використанням двох для циклів у розумінні списку.


11

Я на своєму першому сценарії Python, і мене трохи збентежив приклад квадратної матриці, тому сподіваюся, що наведений нижче приклад допоможе вам заощадити час:

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

так що

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

10

За допомогою NumPy ви можете ініціалізувати порожню матрицю так:

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

А пізніше додайте такі дані:

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

які можуть бути плюси та мінуси використання numpy, а не "списку розуміння"?
Революція для Моніки

7

Я читаю у відокремлених комами файлах так:

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

Потім список "дані" - це список списків із даними індексу [рядок] [коло]


7

Якщо ви хочете мати можливість розглядати це як двовимірний масив, а не змушувати його думати в переліку списків (на мою думку набагато природніше), ви можете зробити наступне:

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

Результат - це список (а не масив NumPy), і ви можете перезаписати окремі позиції цифрами, рядками і будь-якими іншими.


є numpy.matrixеквівалентно numpy.zerosбез нулів без списку?
Революція для Моніки

6

Ось для чого створений словник !

matrix = {}

Ви можете визначити ключі та значення двома способами:

matrix[0,0] = value

або

matrix = { (0,0)  : value }

Результат:

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

6

Використання:

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

Я думаю, що NumPy - це шлях. Наведене вище є загальним, якщо ви не хочете використовувати NumPy.


Мені подобається ця спроба зробити щось просте з ванільним Python, не використовуючи нуд.
Рік Хендерсон

4

за допомогою списку:

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

за допомогою dict: ви також можете зберігати цю інформацію в хеш-таблиці для швидкого пошуку

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

матриця ['1'] дасть результат за час O (1)

* nb : вам потрібно вирішити зіткнення в хеш-таблиці


4

Якщо у вас немає інформації про розмір до початку, створіть два одновимірні списки.

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

Зберігайте весь рядок у 1-му списку. Після завершення додайте список 1 до списку 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

Вихід:

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

Будьте уважні до цього короткого виразу, див. Повне пояснення нижче у відповіді @ FJ


19
Будьте обережні таким чином, тому що Matrix[0], Matrix[1], ..., Matrix[4]всі вказують на один і той же масив, тож після цього Matrix[0][0] = 3, ви б очікували Matrix[0][0] == Matrix[1][0] == ... == Matrix[4][0] == 3.
gongzhitaao

1
Дякуємо gongzhitaao за ваш коментар. Якби я прочитав це еліє, це врятувало б мені щонайменше півгодини. Наявність матриці, де кожен рядок вказує на одне місце в пам'яті, не здається дуже корисним, і якщо ви не знаєте, що ви робите це навіть небезпечно! Я впевнений, що це НЕ те, що хоче зробити Масуд Абасіан, який задав це питання.
Адріан

7
Вам слід видалити цю відповідь, оскільки це неправильна відповідь. Початківці можуть заплутатися.
cxxl

2
На яку відповідь ви звертаєтесь? Я не бачу користувача з іменем "FJ" (навіть у видалених відповідях).
Пітер Мортенсен

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

Буде швидше, ніж:

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

2
Дублікат відповіді одного вже відповіді нижче. Також [[0]*(L) for i in range(W)]має бути , [[0]*(L) for _ in range(W)]так як iніде не використовується
Ayush Ватсьяяна

2

Ви можете створити порожній двовимірний список, вклавши два або більше квадратних дужок або третю дужку ( []розділену комою) за допомогою квадратної дужки , як нижче:

Matrix = [[], []]

Тепер припустимо, що ви хочете додати 1, Matrix[0][0]а потім наберіть:

Matrix[0].append(1)

Тепер наберіть Matrix і натисніть Enter. Вихід буде:

[[1], []]

1

Спробуйте це:

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

1

У випадку, якщо вам потрібна матриця із заздалегідь заданими числами, ви можете використовувати наступний код:

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

Ось фрагмент коду для створення матриці в 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=" ")

Підкажіть, будь ласка, якщо я щось пропустив.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.