For 循环返回不在循环列表中的项目(Python 3.8.6)

时间:2021-05-06 23:53:46

标签: python dictionary for-loop recursion

在我下面的代码中,for 循环传递的值不在正在迭代的列表中。 我正在编写一个简单的寻路函数,其中传递起点和终点,输出是从起点到终点的路径。名为 connection 的字典具有地图上所有点的键,其值是它连接到的所有其他点的列表。您只能通过节点从一个点到达另一个点(认为节点就像道路,字母是房子)。

在这种情况下,我输入了一个起点'A'和一个终点F。预期的输出是:

['A', 'NODE1', 'NODE2', 'NODE4', 'F']

然而,我得到的输出是:

['A', 'NODE1', 'NODE2', 'NODE3', 'NODE4', 'F']

经过一些故障排除后,我发现了一个非常奇怪的问题。在下面的print语句中,最后一次打印如下:

NODE3 ['NODE2', 'C', 'D'] NODE4

打印的格式是:"key, dictionary[key], item inside dictionary[key]" 但是,'item'实际上不在打印的列表中!

我没有改变我正在迭代的键:值对,所以我不知道为什么我会遇到这个问题。我几乎从不在我的函数中使用递归,所以也许这就是问题的来源......有人知道发生了什么吗?

connections = {'A':['NODE1'],
               'B':['NODE1'],
           'NODE1':['A', 'B', 'NODE2'],
           'NODE2':['NODE1', 'NODE3', 'NODE4'],
           'NODE3':['NODE2', 'C', 'D'],
           'NODE4':['NODE2', 'E', 'F'],
           'C':['NODE3'],
           'D':['NODE3'],
           'E':['NODE4'],
           'F':['NODE4']}


def find_path(start_nodes, end):
    nodes = []
    for start in start_nodes:
        if end in connections[start[-1]]:
            s = start
            s.append(end)
            return s
        else:
            for item in connections[start[-1]]:
                print(start[-1], connections[start[-1]], item)
                if 'NODE' in item and item not in start:
                    s = start
                    s.append(item)
                    nodes.append(s)
    find_path(nodes, end)


s = find_path([['A']], 'F')

进一步的代码解释: find_path 接受一个起点列表和一个终点。然后它检查字典以查看连接到起点的内容。如果端点已连接,则返回路径。否则,它会检查连接的节点。一旦找到所有连接的节点,该函数将重新启动,并存储到最近节点的路径,连接的节点现在是起点。直到找到终点为止。

2 个答案:

答案 0 :(得分:1)

Barmar 首先找到了它,但我会拼写出来(我第一次通过自己错过了他的意思)。在函数末尾更改此语句:

find_path(nodes, end)

# print(find_path([['A']], 'F'))
# None

return find_path(nodes, end)

# print(find_path([['A']], 'F'))
# ['A', 'NODE1', 'NODE2', 'NODE3', 'NODE4', 'F']

按照您的方式,您尝试返回的列表不会超过最内层。这样你就可以将它传递到表面。

答案 1 :(得分:1)

我相信发生的事情是通过放置 s = start ,您最终也会修改变量 start 。这就是为什么意外的 NODE3 会成为最终答案的原因

这是因为当你给一个新变量赋值时,它只存储引用号,修改一个变量会修改另一个。

例如

list_values = [1, 2, 3, 4, 5]
new_list = list_values

new_list.append("Interesting")

print("list_values: ", list_values)
print("new_list: ", new_list)

输出:

list_values:  [1, 2, 3, 4, 5, 'Interesting']
new_list:  [1, 2, 3, 4, 5, 'Interesting']

这对于小列表来说是有意义的,但是当您考虑到列表可以包含大量值时,使用参考号会更快

因此,解决方案是我们实际上需要将整个列表复制到“s”,而不仅仅是引用编号。

为此:

import copy

s = copy.deepcopy(start) # use this instead of s = start

最终代码:

connections = {'A':['NODE1'],
               'B':['NODE1'],
           'NODE1':['A', 'B', 'NODE2'],
           'NODE2':['NODE1', 'NODE3', 'NODE4'],
           'NODE3':['NODE2', 'C', 'D'],
           'NODE4':['NODE2', 'E', 'F'],
           'C':['NODE3'],
           'D':['NODE3'],
           'E':['NODE4'],
           'F':['NODE4']}

import copy

def find_path(start_nodes, end):
    global s

    nodes = []
    for start in start_nodes:
        if end in connections[start[-1]]:
            s = copy.deepcopy(start)
            s.append(end)
            return s
        else:
            for item in connections[start[-1]]:
                if 'NODE' in item and item not in start:
                    s = copy.deepcopy(start)
                    s.append(item)
                    nodes.append(s)
    find_path(nodes, end)


find_path([['A']], 'F')
print(s)

输出:['A', 'NODE1', 'NODE2', 'NODE4', 'F']

编辑: 看起来我发布这个答案已经晚了,@Jamie Deith 和 @Barmar 已经回答了。无论如何,我已经提到了为什么它没有按预期工作,所以这仍然会有所帮助。

相关问题