Python: обновление двумерного массива словарей
Я работаю над проектом q-learning, который включает в себя круг, решающий лабиринт, и это проблема с тем, как я обновляю значения Q, но я не уверен, где: я законно потратил 3 дня на эту тему, и я Я в моем конце ума.
При ближайшем рассмотрении кажется, что все наборы словарей в каждой строке Q одинаковы (например: значение [Direction.up] в строке 3 всегда равно 22, даже если это не так)
Любые указатели приветствуются, вот код, о котором идет речь, надеюсь, вы сможете сами его протестировать:
rows=cols=10
for i in range(rows):
Q.append([{}]*(cols))
for x in range (cols):
for y in range (rows):
Q[x][y][Direction.up]=0
Q[x][y][Direction.down]=0
Q[x][y][Direction.left]=0
Q[x][y][Direction.right]=0
x=5
y=2
Q[x][y][Direction.right]=22
for x in range (cols):
for y in range (rows):
print(x," ",y)
print(Q[x][y])
print("\n")
print("\n")
2 ответа
Одной из основных проблем является структура данных. Я предполагаю, что вы хотите сохранить одно значение для x, y и направления. Но если вы инициализируете свой список словарей с умножением
Q = [{}] * 10
Вы получите список из десяти раз одного и того же словаря, а не десяти разных:
>>> Q = [{}] * 10
>>> Q
[{}, {}, {}, {}, {}, {}, {}, {}, {}, {}]
>>> Q[0]["k"] = "v"
>>> Q
[{'k': 'v'}, {'k': 'v'}, {'k': 'v'}, {'k': 'v'}, {'k': 'v'}, {'k': 'v'}, {'k': 'v'}, {'k': 'v'
}, {'k': 'v'}, {'k': 'v'}]
Так что либо инициализируйте словарь в цикле
>>> Q = [{} for _ in range(10)]
>>> Q
[{}, {}, {}, {}, {}, {}, {}, {}, {}, {}]
>>> Q[0]["k"] = "v"
>>> Q
[{'k': 'v'}, {}, {}, {}, {}, {}, {}, {}, {}, {}]
или используйте только один словарь с кортежем (x, y, direction)
в качестве ключа:
Q = {}
for x in range(rows):
for y in range(cols):
for dir in Direction:
Q[(x, y, dir)] = 0
Таким образом, актуальная проблема заключается в том, что вы создаете список cols
повторения словаря {}
,
a = [{}]*3
b = [{} for _ in range(3)]
print(id(a[0]), id(a[1]), id(a[2])) # returns 3 times the same identity
print(id(b[0]), id(b[1]), id(b[2])) # returns 3 different identities
Проблема в том, что оператор умножения *
определяется для работы на объектах. Таким образом, сначала вычисляется выражение, затем объект умножается. В понимании выражение вычисляется на каждой итерации.
*
Оператор не знает, что у вас есть выражение внутри вашего объекта и / или вы хотите скопировать любую его часть. Таким образом, он генерирует ссылки на один и тот же объект вместо создания новых. Такое поведение оператора умножения является фундаментальной частью языкового дизайна, и поэтому нам, пользователям Python, придется адаптироваться к работе с ним.
Кстати, то же самое происходит для rows
а также cols
определение.
rows = cols = 10
print(id(rows), id(cols)) # identities match
Тем не менее, поскольку целые числа неизменяемы, вы не будете менять cols
если вы переопределите rows
rows = [3]
print(rows, cols) #[3] 10
Если бы вы использовали изменяемые объекты, вы бы столкнулись с тем же поведением, которое вы видите в текущей проблеме со списком словарей:
rows = cols = {}
rows.update({1: 'a'})
print(rows, cols) #{1: 'a'} {1: 'a'}
Теперь, где же это оставляет нас в нашем стремлении обновить ваши словари так, как вы этого хотите (я позволил себе адаптировать некоторые части кода там, где я думал, что это избыточно):
rows=cols=10
for i in range(rows):
Q.append([{} for _ in range(cols)])
for x in range(cols):
Q[x][i][Direction.up]=0
Q[x][i][Direction.down]=0
Q[x][i][Direction.left]=0
Q[x][i][Direction.right]=0
x=5
y=2
Q[x][y][Direction.right]=22
for x in range(cols):
for y in range(rows):
print(x, ' ', y, '\n', Q[x][y], '\n', sep='')
print("\n")