Как определить двумерный массив в Python

726

Я хочу определить двумерный массив без инициализированной длины следующим образом:

Matrix = [][]

Но это не работает...

Я пробовал код ниже, но это тоже неправильно:

Matrix = [5][5]

Ошибка:

Traceback ...

IndexError: list index out of range

В чем моя ошибка?

Масуд Абасян
источник
14
Никто не определяет массивы или любую другую вещь. Вы можете, однако, создавать многомерные последовательности, как показывают ответы здесь. Помните, что переменные python нетипизированы, но значения строго типизированы.
SingleNegationElimination
1
Я смущен. Исходя из других языков: это разница между 1D-массивом, содержащим 1D-массивы и 2D-массивом. И у AFAIK нет способа иметь многомерный массив (или список) в python. Должно быть сказано здесь ...
Дирк Рейхель
1
См. Также FAQ по Python3, как создать многомерный список?
Кевин W Мэтьюз

Ответы:

1011

Технически вы пытаетесь проиндексировать неинициализированный массив. Вы должны сначала инициализировать внешний список списками, прежде чем добавлять элементы; 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 для диапазона х (cols_count)] для диапазона х (row_count)]
сонгир
3
Нечетное редактирование от ademar111190. В Python 3 нет xrange, но если вы должны использовать Python 2, тогда xrange - это правильная функция, которую нужно использовать, если вы не хотите создавать объекты без необходимости.
Дейв
4
@dave Если вам не нужно заполнять нулями, можете использовать rangeдля создания внутренних списков напрямую:[range(5) for x in range(5)]
alanjds
2
@alanjds - это правда, но вы все равно создаете потенциально много ненужных ссылок на объекты в Python 2 для внешней итерации (попробуйте это с ОЧЕНЬ большим диапазоном). Кроме того, инициализация какого-либо значения почти всегда является тем, что вам нужно - и это чаще всего 0, а range дает итеративную коллекцию - 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
408

Если вы действительно хотите матрицу, вам лучше использовать 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.]])

Вот некоторые другие способы создания двумерных массивов и матриц (с выходом, удаленным для компактности):

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в будущем.

senderle
источник
80
Всякий раз, когда вы хотите матрицы, вы хотите использовать NumPy. Этот ответ должен быть первым.
Пэт Б
3
Тот факт, что в вопросе используется английское слово «матрица», не означает, что они должны использовать его np.matrixдля представления. Правильный способ представить матрицу в NumPy с помощью array.
user2357112 поддерживает Monica
@ user2357112, и, как вы можете видеть, большинство приведенных выше примеров выводят arrays вместо матриц. Хотя это не всегда поощряется, существуют законные причины для использования matrix- контекст имеет значение.
senderle
1
@senderle, можете ли вы рассказать о причинах использования matrix? С тех пор, как @оператор был введен, кажется, есть еще одна причина, так как этот пост был написан.
JPP
1
@jpp, как уже говорилось в сообщении, люди из Matlab могут найти его полезным. Но numpyсейчас документы показывают, что класс может быть исключен и удален в будущем, поэтому я исключил его из ответа.
senderle
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 ведет себя как значение - или вы можете думать о нем как о примитивном типе данных - потому что он неизменный, поэтому у вас никогда не
возникнет
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)]
mripard
источник
@KorayTugay Поскольку матрица представлена ​​с использованием списка (ей) Python (строк), вложенных в другой список (столбцы).
Элиг
2
Для Python-3 вместо функции xrange используется функция range
Ракеш Чаудхари
77

Если вам нужен только двумерный контейнер для хранения некоторых элементов, вы можете вместо этого использовать словарь:

Matrix = {}

Тогда вы можете сделать:

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

Это работает, потому что 1,2это кортеж, и вы используете его в качестве ключа для индексации словаря. Результат похож на тупую разреженную матрицу.

Как указано osa и Josap Valls, вы также можете использовать Matrix = collections.defaultdict(lambda:0)так, чтобы отсутствующие элементы имели значение по умолчанию 0.

Далее Ватсал отмечает, что этот метод, вероятно, не очень эффективен для больших матриц и должен использоваться только в не критичных для производительности частях кода.

enobayram
источник
2
Тогда вы также можете сделать import collections; Matrix = collections.defaultdict(float), чтобы заменить нули на неинициализированные элементы.
Оса
2
Не будет доступа к dict для tuple (1,2) в качестве ключа, сложность в худшем случае O (n). Как и внутри, он бы хешировал кортежи. Принимая во внимание, что использование двумерного массива даст O (1) временную сложность для доступа к индексу [1,2] доступа. Поэтому использование dict для этого не должно быть хорошим выбором.
Ватсал
@Vatsal wiki.python.org/moin/TimeComplexity говорит, что средний случай равен O (1), но вы правы в худшем случае. Во всяком случае, если вы не говорите о большом количестве предметов, вы бы не заботились об этой разнице. На самом деле, я бы больше беспокоился о памяти, чем о времени доступа.
энобайрам
Также мы всегда стараемся избегать использования dicts, пока общая сложность алгоритма не станет равной или большей, чем 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)

Теперь matrix [0] [0] == 2 и matrix [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)]
wberry
источник
6
extendБыло бы также полезно в первом случае: если вы начнете с m = [[]], то вы можете добавить к внутреннему списку (расширить строку) с помощью m[0].extend([1,2]), и добавить к внешнему списку (добавить новую строку) с помощью m.append([3,4]), эти операции оставят вас с [[1, 2], [3, 4]].
Askewchan
22

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

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

результаты в

[[], [], []]
Fabian
источник
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
utdemir
источник
На самом деле последовательность для 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 для первого измерения работает, потому что на этом уровне данные неизменны.

innov8
источник
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)]

Я нахожу этот синтаксис легко запоминающимся по сравнению с использованием двух циклов for в понимании списка.

Майкл
источник
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
user110954
источник
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)

Список «data» - это список списков с индексом data [row] [col]

wsanders
источник
7

Если вы хотите иметь возможность думать о нем как о двумерном массиве, а не думать о нем как о списке списков (на мой взгляд, это более естественно), вы можете сделать следующее:

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

Результатом является список (не массив NumPy), и вы можете перезаписать отдельные позиции числами, строками и так далее.

alessadnro
источник
являются 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.

pterodragon
источник
Мне нравится эта попытка сделать что-то простое с ванильным Python без необходимости использовать numpy.
Рик Хендерсон
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=" ")

Пожалуйста, предложите, если я что-то пропустил.

Чандра Шекхар
источник