0

以下の関数 (この場合はメソッド) は、反復中にリストを変更するため、役に立たないと誰かが言いました。意図したとおりに機能するのはなぜですか。私は実際にそれに非常に満足していました.それを書くより良い方法はありますか.

データ構造、機能、および出力は次のとおりです。

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') ]
4

2 に答える 2

3

次の 3 つの例を考えてみましょう。

l = [1]
for x in l:
    if x < 10 # avoid infinite loop
         l.append(x+1)
    print x

このコードは正しく、使用しているものと似ています。出力は予想どおり 1..10 です。for ループに項目を追加しても問題ありません (または、現在の反復子位置の後に項目を挿入します)。

同じ例を代わりに挿入して試してください。

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,2,3,4,5 とは 1,3,5 異なります。したがって、現在のイテレータの前にアイテムを削除することも悪いことです。

簡単にするために、ループ中にリストの内容を変更することは、自分が何をしているのか、またそれが出力にどのような影響を与える可能性があるのか​​ を正確に把握していない限り、避けるべきであるとだけ言っておきましょう。

于 2012-06-19T11:27:00.300 に答える
2

反復しているリストへの追加は安全です。コード レビュー担当者がそれを受け入れない場合、またはまだぎくしゃくしている場合は、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 = []
于 2012-06-19T11:43:32.723 に答える