有人提到下面的函数(在本例中是一个方法)并不好,因为它在迭代时修改了一个列表。为什么这样,因为它完全符合我的预期。我其实很满意......有没有更好的写作方式。
数据结构,功能和输出如下:
nodes = { ('foo','bar',1),
('foo','baz',1),
('baz','gad',0),
('boo','moo',1),
('goo','loo',0),
('bar','far',1),
('far','aaa',0) }
class Graph(dict):
def __missing__(self, key):
self[key] = set()
return self[key]
def add_node_pairs(self, node_pairs):
for pair in node_pairs:
nodeA, nodeB, weight = pair
self[nodeA].add((weight, nodeB))
self[nodeB].add((weight, nodeA))
def find_paths(self, keys):
paths = [(key,) for key in keys if key in self]
for path in paths:
*oldkeys, key = path
for weight, next_key in self[key]:
if next_key not in oldkeys:
paths.append( path + (weight,next_key) )
paths.sort()
return paths
graph = Graph()
graph.add_node_pairs(nodes)
print(graph)
print( graph.find_paths(['foo']))
图:
{ 'goo': {(0, 'loo')},
'foo': {(1, 'bar'), (1, 'baz')},
'aaa': {(0, 'far')},
'far': {(1, 'bar'), (0, 'aaa')},
'baz': {(0, 'gad'), (1, 'foo')},
'loo': {(0, 'goo')},
'moo': {(1, 'boo')},
'boo': {(1, 'moo')},
'bar': {(1, 'far'), (1, 'foo')},
'gad': {(0, 'baz')} }
find_paths(' foo'):
[ ('foo',),
('foo', 1, 'bar'),
('foo', 1, 'bar', 1, 'far'),
('foo', 1, 'bar', 1, 'far', 0, 'aaa'),
('foo', 1, 'baz'),
('foo', 1, 'baz', 0, 'gad') ]
答案 0 :(得分:3)
考虑以下三个例子:
l = [1]
for x in l:
if x < 10 # avoid infinite loop
l.append(x+1)
print x
此代码是正确的,与您正在使用的代码类似。输出如预期1..10。 在for循环上附加项是可以的(或者在当前迭代器位置之后插入一个项)。
现在尝试相同的示例,但改为使用insert:
l = [1]
for x in l:
if x < 10 # avoid infinite loop
l.insert(0,x+1)
print x
这一次,你最终会得到一个无限循环。原因是for循环将始终检查下一个项目,因为我们在开头插入x,所以选中的项目将始终等于1.在当前迭代器位置之前插入项目通常是错误的。
最后检查一下这个例子:
l = [1,2,3,4,5]
for x in l:
print x
l.remove(x)
此函数的输出将与预期输出的1,3,5不同:1,2,3,4,5。 因此,在当前迭代器之前删除项目也很糟糕。
为简化起见,我们只是说应该避免在循环时更改列表的内容,除非您确切知道自己在做什么以及它可能对输出产生什么影响。
答案 1 :(得分:2)
附加到您正在迭代的列表是安全的。如果您的代码审核人员不接受,或者您仍觉得软弱,则可以使用两阶段方法:
paths = [blah blah]
next_paths = []
while paths:
for path in paths:
if something_or_other:
next_paths.append(blah)
paths = next_paths
next_paths = []