卡在这个函数

huangapple go评论72阅读模式
英文:

Stuck on this function

问题

num_ended_games += 1
英文:
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): {}}}}
    """

i've been trying to solve this function but i'm kinda stuck. I know how to write the general structure but have no idea how to get the number correctly. Can someone help implement

this is what I've done:

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

and the error messages are

Failed example:
d

Expected:

{('a', 0): {('b', 1): {('c', 1): {}}}, ('d', 0): {('e', 2): {}}}

Got:

{('a', 0): {('b', 0): {('c', 0): {}}}, ('d', 0): {('e', 0): {}}}

答案1

得分: 1

以下是代码部分的翻译:

你之前在使用嵌套的for循环方面是正确的但是

> ```py
>     num_ended_games = 0 ## 循环开始
> ```
> ```py
>         key = (move, num_ended_games)
>         if key not in current_dict:
> ```
> ```py
>     num_ended_games += 1 ## 循环结束
> ```

在循环结束时增加`num_ended_games`,但没有在任何地方设置它这不会更新`result`字典中的值要[更改字典键](https://stackoverflow.com/a/4406521/6146136)你需要将旧值设置为新键并使用[`del`](https://www.programiz.com/python-programming/del)或[`.pop`](https://www.programiz.com/python-programming/methods/dictionary/pop)删除旧键此外请记住元组在Python中是[不可变的](https://realpython.com/python-mutable-vs-immutable-types/#mutability-vs-immutability),因此要更改元组中的一个值,你需要替换整个元组...

尝试使用以下版本的`moves_to_nested_dict`。 <sup>([查看示例输出][1])</sup>

```py
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

<sup>[使用 enumeratestart=1-len 来使 reverse_index1-len 开始计数,直到 0 - 这样我们可以用它来跟踪剩下多少步骤以及何时到达最后一步;而壁鼠操作符 (:=) 只是一种方便的方式,用一条语句定义/更新并使用变量,而不需要在使用之前先设置它。]</sup>

<br>


<br>

顺便说一句,如果num_ended_games是字典内的一个值,那么这将更简单,因此只需使用move作为键,而不需要检查并有时更新键,你可以使用.setdefault

def moves_to_nested_dict(moves: list[list[str]]) -&gt; 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

<sup>[在不能确定键是否存在时,使用 <dict>.get(<key>)&lt;dict&gt;[&lt;key&gt;] 更安全。]</sup>

使用此版本,

moves_to_nested_dict([['a','b'], ['a','b'], ['a','b','c'], ['d','a'], ['a','d']])

将返回

> py &gt; { &gt; 'a': { &gt; '__games_ended__': 0, &gt; 'b': {'__games_ended__': 2, 'c': {'__games_ended__': 1}}, &gt; 'd': {'__games_ended__': 1} &gt; }, &gt; 'd': {'__games_ended__': 0, 'a': {'__games_ended__': 1}} &gt; } &gt;

英文:

You were on the right track with nested for-loops, but

> py
&gt; num_ended_games = 0 ## beginning of loop
&gt;

> py
&gt; key = (move, num_ended_games)
&gt; if key not in current_dict:
&gt;

> py
&gt; num_ended_games += 1 ## end of loop
&gt;

Incrementing num_ended_games at the end of loop without setting it anywhere does not update it in the result dictionary. To change a dictionary key you need to set the old value to the new key and del or .pop the old key. Also, keep in mind that tuples are not mutable in python, so to change one value in a tuple, you need to replace the whole tuple...

Try something like the version of moves_to_nested_dict below. <sup>(view example outputs)</sup>

def moves_to_nested_dict(moves: list[list[str]]) -&gt; 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: ## &lt;-- 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

<sup>[Using enumerate with start=1-len makes reverse_index count starting from 1-len and ending at 0 - so we can use that to keep track of how many moves are left and when we're on the last move; and the walrus operator (:=) is just a handy way of defining/updating and using a variable in one statement instead of needing an extra line to set it first before using it.]</sup>

<br>


<br>

Btw, this would be much simpler if num_ended_games was a value inside the dictionary so that just move could be used as the key, and you could just use .setdefault instead of needing to check for and sometimes update the key:

def moves_to_nested_dict(moves: list[list[str]]) -&gt; dict[str,dict]:
    result = {}
    for game in moves:
        cur_dict = result
        for move in game: 
            cur_dict = cur_dict.setdefault(move, {&#39;__games_ended__&#39;:0}) # (move,{})
        if game: cur_dict[&#39;__games_ended__&#39;] = cur_dict.get(&#39;__games_ended__&#39;,0)+1
    return result

<sup>[Using &lt;dict&gt;.get(&lt;key&gt;) is safer than &lt;dict&gt;[&lt;key&gt;] when you can't be sure that the key exists.]</sup>

With this version,

moves_to_nested_dict([[&#39;a&#39;,&#39;b&#39;], [&#39;a&#39;,&#39;b&#39;], [&#39;a&#39;,&#39;b&#39;,&#39;c&#39;], [&#39;d&#39;,&#39;a&#39;], [&#39;a&#39;,&#39;d&#39;]])

would return

> py
&gt; {
&gt; &#39;a&#39;: {
&gt; &#39;__games_ended__&#39;: 0,
&gt; &#39;b&#39;: {&#39;__games_ended__&#39;: 2, &#39;c&#39;: {&#39;__games_ended__&#39;: 1}},
&gt; &#39;d&#39;: {&#39;__games_ended__&#39;: 1}
&gt; },
&gt; &#39;d&#39;: {&#39;__games_ended__&#39;: 0, &#39;a&#39;: {&#39;__games_ended__&#39;: 1}}
&gt; }
&gt;

huangapple
  • 本文由 发表于 2023年4月4日 10:18:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/75925033.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定