Назначение значения отдельной ячейке в двухмерном массиве python

Скажем, у меня есть следующий пустой двухмерный массив в Python:

q = [[None]*5]*4

Я хочу присвоить значение 5 первой строке в первом столбце q. Инстинктивно я делаю следующее:

q[0][0] = 5

Однако это дает:

 [[5, None, None, None, None], 
  [5, None, None, None, None], 
  [5, None, None, None, None], 
  [5, None, None, None, None]]

Первый элемент каждого массива инициализируется на 5, где я думал, что только первый элемент первого массива получит обновление. У меня есть два вопроса:

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

Ответы

Ответ 1

Это не делает то, что вы надеялись.

q = [[None]*5]*4

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

Один список со значением [None] используется пять раз.

Один список со значением [[None]*5] используется четыре раза.

q = [ [ None for i in range(5) ] for j in range(4) ]

Может быть больше того, что вы ищете.

Это явно избегает повторного использования объекта списка.

80% времени, словарь - это то, что вы действительно хотели.

q = {}
q[0,0]= 5

Будет также работать. Вы не начинаете с предопределенной сетки значений None. Но это редко нужно в первую очередь.

В Python 2.7 и выше вы можете это сделать.

q = { (i,j):0 for i in range(5) for j in range(4) }

Это построит сетку, индексированную по 2-мя кортежами.

{(0, 1): 0, (1, 2): 0, (3, 2): 0, (0, 0): 0, (3, 3): 0, (3, 0): 0, (3, 1): 0, (2, 1): 0, (0, 2): 0, (2, 0): 0, (1, 3): 0, (2, 3): 0, (4, 3): 0, (2, 2): 0, (1, 0): 0, (4, 2): 0, (0, 3): 0, (4, 1): 0, (1, 1): 0, (4, 0): 0}

Ответ 2

Причина, по которой у вас есть список, просто повторяется четыре раза! Python не регенерирует этот список каждый раз, когда вы делаете *4. Он использует тот же объект списка.

Чтобы обойти это, вам нужно, чтобы force python каждый раз регенерировал этот список:

[ [None] * 5 for i1 in range(4) ]

В этом случае я использую понимание списка.

Ответ 3

q = [[None]*5]*4
print(q)
q[1][1]=4
print(q)
q = [ [ None for i in range(5) ] for j in range(4) ]
q[1][1]=4
print(q)

результат:

[[None, None, None, None, None], [None, None, None, None, None], [None, None, None, None, None], [None, None, None, None, None]]
[[None, 4, None, None, None], [None, 4, None, None, None], [None, 4, None, None, None], [None, 4, None, None, None]]
[[None, None, None, None, None], [None, 4, None, None, None], [None, None, None, None, None], [None, None, None, None, None]]

Ответ 4

Ответ прост Никогда не используйте

q = [[None]*5]*4

как при назначении

q[0][1]=5 он присваивает значение несколько раз нескольким строкам в 1 столбце попробуйте распечатать (q)

скорее используйте

q = { (i,j):0 for i in range(5) for j in range(4) }

то q[0][1]=5 будет назначаться только один раз попробуйте

print(q)

Ответ 5

Почему Python инициализирует первое значение каждого массива, а не только первое?

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

Есть ли лучший способ выполнить то, что я пытаюсь сделать?

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

Ответ 6

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

q[0] = [5,None,None,None,None]

Ответ 7

Ответ на вопрос № 2: Использование numpy - это опция. См. Следующий код.

import numpy as np

# creating 2D array with nans
num_of_rows = 5
num_of_cols = 3
a = np.full((num_of_rows, num_of_cols), np.nan) 
#for zero vals: a = np.zeros((num_of_rows, num_of_cols))

# placing number 5 in row 3, col 1
value = [5]
position_row = 3
position_col = 1
# the put command below flattens the 2D array
position = [int(num_of_cols * position_row + position_col)] 
np.put(a, position, value)

результат:

[[ nan  nan  nan]
 [ nan  nan  nan]
 [ nan  nan  nan]
 [ nan   5.  nan]
 [ nan  nan  nan]]