0

タイムスタンプ付きの辞書があり、それを繰り返し処理して、古いと見なされるアイテムを削除したい(Pythonの場合)これをどうすればよいですか?このコードはRuntimeErrorを与えます:反復中に辞書のサイズが変更されました

    for key, value in img_dict.iteritems() :
        if (time.time()-float(img_dict[key])) >= stale_img:
            logger.debug('STALE IMAGE FROM '+hexlify(key)+ ' - GOT CLOSED NOW!')
            del img_dict[key]
            data_upload = True
4

2 に答える 2

4

コレクションを反復処理している間は、コレクションを変更できません。

これを回避する方法はいくつかあります。

  • (0)設計を再考して、これを行う必要があるかどうかを確認します。
  • (1)コレクションを変更しないでください。代わりに、フィルタリングされた新しいコレクションを作成します。
  • (2)コレクションを繰り返さないでください。代わりに、コレクションのコピーを繰り返し処理します
  • (2.5)ディクショナリの場合、キーのコピーを繰り返し処理し、値を明示的にフェッチします。

アイテムを繰り返し処理しているにもかかわらず、すでに値を明示的にフェッチしていることに注意してください。したがって、ここで#2を使用する理由はありません。

他の2つの実装は次のとおりです。

new_img_dict = {}
for key in img_dict:
    if (time.time()-float(img_dict[key])) >= stale_img:
        logger.debug('STALE IMAGE FROM '+hexlify(key)+ ' - GOT CLOSED NOW!')
        data_upload = True
   else:
       new_img_dict[key] = img_dict[key]
img_dict = new_img_dict

または:

for key in img_dict.keys():
    if (time.time()-float(img_dict[key])) >= stale_img:
        logger.debug('STALE IMAGE FROM '+hexlify(key)+ ' - GOT CLOSED NOW!')
        del img_dict[key]
        data_upload = True

(これをPython 3と互換性があるようにする場合は、ではなくimg_dict.keys()、実行してくださいimg_dict.keys()[:]。)

では、どのように2つを選択しますか?

1つ目は、一般的に推論が容易です。一般に、不変オブジェクトと純粋な操作は、推論が容易です。たとえば、どこかで例外をスローした場合、その中間でimg_dictはなく、常に元のバージョンまたは完成したバージョンがあります。そしてもちろん、それを繰り返しながら何かを変更することの意味を考える必要はありません。ただし、まれに、「foo以外のすべてを削除する」アルゴリズムを「foo以外のすべてをコピーする」アルゴリズムに変換するのが難しい場合があります。

最初のものは、通常、理解(またはのような高階関数の呼び出し)として書き直したりfilter、ジェネレーターに変換したり、リファクタリングして個別の関数を引き出したりするのがはるかに簡単です。

パフォーマンスのために、多くの値を除外する場合、最初の値は一般的に高速でメモリの使用量が少なくなりますが、ほとんどの値を保持する場合は通常、2番目の方が優れています。(カットオフはコレクションの種類によって異なります。通常のように、問題になることはめったにありません。問題がある場合は、方法とプロファイルの両方を記述する必要があります。)

#0に戻ると、この場合に当てはまると思います。すべてのキーを調べて、古いキーがないかどうかを確認し、キーを削除します。たとえば、並べ替えられたリストや優先度付きキューを使用した場合は、それを行う必要はありません。これで、古い値をフラッシュする必要があるよりも頻繁にコレクションを使用する必要がある場合はdict、データ構造を変更することによるメリットよりもコストがかかる可能性があります。しかし、なぜ両方を持っていないのですか?キーを値にマッピングするディクショナリの上に、ソートされたキーのリストがある場合は、次のようにすることができます。

for key in img_sorted_key_list:
    if time.time() - float(key) > stale_img:
        break
    del img_dict[key]

または、もっと簡単に:

stale_time = time.time() - stale_img
for key in itertools.takewhile(lambda key: float(key) < stale_time, 
                               img_sorted_key_list):
    del img_dict[key]

Cacheそして、ソートされたキーリストと辞書を一緒に素敵なクラスか何かにラップすることができます。

于 2012-12-13T23:25:18.523 に答える
1

この例を見てください。多分それは役に立つでしょう。リストまたは辞書の要素を削除するときは、最後から始めることを忘れないでください。iteritems()メソッドの使用は避けてください。

keysMap = [
      {"key": 1 },
      {"key" : 2 },
      {"key" : 3 },
      {"key" : 4 },
      {"key" : 5 },
      {"key" : 6 }
       ]   
i=len(keysMap)-1
while i > 0 :
    key = keysMap[i]
    if key["key"]==2 :
        del(keysMap[i])
    i=i-1

# Printing the object data after deleting element key=2    
while i < len(keysMap) :
    key = keysMap[i]
    print key
    i=i+1 
于 2012-12-14T01:43:52.083 に答える