def moves_to_nested_dict(moves: list[list[str]]) -> dict[tuple[str, int], dict]:
"""
Convert <games> into a nested dictionary representing the sequence of moves
made in the games.
Each list in <games> corresponds to one game, with the i'th str being the
i'th move of the game.
The nested dictionary's keys are tuples containing the string representing
the move made on that turn and an integer indicating how many games ended
immediately after this move. See the docstring example below.
The values of each nested dictionary are themselves nested dictionaries of
this structure. An empty dictionary is stored as the value for a move that
will correspond to a leaf
Note: to keep the docstring short, we use single letters in place
of real chess moves, as it has no impact on the logic of how this
code needs to be implemented, since it should work for arbitary
strings used to denote moves.
>>> moves_to_nested_dict([[]]) # empty lists are ignored
{}
>>> moves_to_nested_dict([])
{}
>>> moves_to_nested_dict([['a'], []])
{('a', 1): {}}
>>> d = moves_to_nested_dict([["a", "b", "c"],
... ["a", "b"], ["d", "e"], ["d", "e"]])
>>> d
{('a', 0): {('b', 1): {('c', 1): {}}}, ('d', 0): {('e', 2): {}}}
>>> d = moves_to_nested_dict([
... ["a", "b", "c"], ["a", "b"], ["d", "e", "a"], ["d", "e"]])
>>> d
{('a', 0): {('b', 1): {('c', 1): {}}}, ('d', 0): {('e', 1): {('a', 1): {}}}}
"""
我一直在试图解决这个功能,但我有点卡住了。我知道如何写出总体结构,但不知道如何得到正确的数字。有人能帮忙实现
吗?这就是我所做的:
result = {}
for game_moves in moves:
if len(game_moves) == 0:
continue
current_dict = result
num_ended_games = 0
for move in game_moves[:-1]:
key = (move, num_ended_games)
if key not in current_dict:
current_dict[key] = {}
current_dict = current_dict[key]
num_ended_games = 0
last_move = game_moves[-1]
key = (last_move, num_ended_games)
if key not in current_dict:
current_dict[key] = {}
current_dict = current_dict[key]
num_ended_games += 1
return result
,错误信息为
失败的例子:d
:
{('a', 0): {('b', 1): {('c', 1): {}}}, ('d', 0): {('e', 2): {}}}
有:
{('a', 0): {('b', 0): {('c', 0): {}}}, ('d', 0): {('e', 0): {}}}
嵌套for循环是正确的,但是
num_ended_games = 0 ## beginning of loop
key = (move, num_ended_games) if key not in current_dict:
num_ended_games += 1 ## end of loop
在循环结束时增加num_ended_games
而不设置它,不会在result
字典中更新它。要更改字典键,需要将旧值设置为新键,并将del
或.pop
设置为旧键。另外,请记住,元组在python中是不可变的,因此要更改元组中的一个值,您需要替换整个元组…
试试下面的moves_to_nested_dict
版本。(查看示例输出)
def moves_to_nested_dict(moves: list[list[str]]) -> dict[tuple[str,int], dict]:
result = {}
for game_moves in moves:
cur_dict = result
for reverse_index, move in enumerate(game_moves, 1-len(game_moves)):
cur_key = [k for k in cur_dict if k[0]==move]
if not cur_key: cur_dict[(cur_key := (move, 0))] = {}
else: cur_key = cur_key[0]
if not reverse_index: ## <-- reverse_index=0 on last move
cur_dict[(move, cur_key[1]+1)] = cur_dict.pop(cur_key)
else: cur_dict = cur_dict[cur_key]
return result
[使用enumerate
和start=1-len
使reverse_index
计数从1-len
开始并以0结束-因此我们可以使用它来跟踪剩余的移动数以及我们在最后一次移动时;和海象操作符(:=
)只是一个方便的方式来定义/更新和使用一个变量在一个语句,而不是需要额外的行设置它之前使用它。]
顺便说一句,如果num_ended_games
是字典中的值,这样就可以使用move
作为键,您可以只使用.setdefault
而不需要检查和有时更新键:
def moves_to_nested_dict(moves: list[list[str]]) -> dict[str,dict]:
result = {}
for game in moves:
cur_dict = result
for move in game:
cur_dict = cur_dict.setdefault(move, {'__games_ended__':0}) # (move,{})
if game: cur_dict['__games_ended__'] = cur_dict.get('__games_ended__',0)+1
return result
[当不能确定密钥是否存在时,使用<dict>.get(<key>)
比使用<dict>[<key>]
更安全]
在这个版本中,
moves_to_nested_dict([['a','b'], ['a','b'], ['a','b','c'], ['d','a'], ['a','d']])
回来{ 'a': { '__games_ended__': 0, 'b': {'__games_ended__': 2, 'c': {'__games_ended__': 1}}, 'd': {'__games_ended__': 1} }, 'd': {'__games_ended__': 0, 'a': {'__games_ended__': 1}} }