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")
Другие вопросы по тегам