Назначение значения отдельной ячейке в двухмерном массиве 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]]