如何从迭代的字典中删除一个项目? [英] how to remove an item from a dictionary that is iterated?

查看:120
本文介绍了如何从迭代的字典中删除一个项目?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有时间戳的字典,我想迭代它,并删除被认为是过时的项目(在Python中)
我最好怎么做?
此代码给我 RuntimeError:字典在迭代期间更改大小

 在img_dict.iteritems()中的值:
if(time.time() - float(img_dict [key]))> = stale_img:
logger.debug('STALE IMAGE FROM'+ hexlify )+' - GOT CLOSED NOW!')
del img_dict [key]
data_upload = True


解决方案

在迭代过程中您不能修改集合。



有几种方法: (1)重新设计你的设计,看看是否需要这样做。

  • (1)不要修改收藏;相反,构建一个新的过滤集合。

  • (2)不要遍历集合;相反,迭代集合的副本

  • (2.5)对于字典,迭代键的副本,并显式获取值。



  • 请注意,尽管迭代了项目,您已经明确地获取了这些值,所以没有理由在#2这里。



    这里是另外两个的实现:

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

    或:

     为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(),do img_dict.keys()[:] 。)



    那么你如何在两者之间进行选择?



    第一个通常更容易理解 - 一般来说,不可变对象和纯粹的操作很容易理解。例如,如果您在某个地方引发异常, img_dict 将始终具有原始版本或完整版本,而不是中间版本。当然,你不必考虑在迭代过程中改变某些东西的意义。然而,在一些罕见的情况下,很难将将foo中的所有内容删除到复制所有不在foo的算法。



    第一个也是通常更容易重写为一个理解(或调用高阶函数,如 filter ),变成一个生成器,重构以提取单独的函数等。 / p>

    对于性能来说,第一个通常会更快,如果您滤除许多值,则使用较少的内存,而如果您保留最多,则第二个通常会更好值。 (对于不同的收集类型,截止值是不同的。通常情况下,很少有重要的事情,如果有的话,你应该写这两种方式和简档。)



    回到#0,我认为这可能适用于这种情况。你正在走过所有的钥匙,看看有没有太老,要去除它们。如果您使用,例如排序列表或优先级队列,则不需要这样做。现在,如果您需要更频繁地使用集合作为 dict ,您需要刷新旧值,那么您可能会从更改数据结构中获得更多的成本。但是为什么不同时拥有?如果你有一个排序的键列表,在字典的顶部将键映射到值,那么你可以这样做:

     关键在img_sorted_key_list:
    如果time.time() - float(key)> stale_img:
    break
    del img_dict [key]

    或者,

      stale_time = time.time() -  stale_img 
    为itertools.takewhile中的键(lambda键:float(键)< stale_time,
    img_sorted_key_list):
    del img_dict [key]

    您可以将排序的密钥列表和字典合并到一个不错的缓存类或某些东西。


    I have a dictionary with timestamps and I want to iterate through it and remove the items that are considered outdated (in Python) How do I best go about this? This code gives me RuntimeError: dictionary changed size during iteration:

        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
    

    解决方案

    You can't modify collections while iterating over them.

    There are a few ways around this:

    • (0) Rethink your design to see if you need to do this.
    • (1) Don't modify the collection; instead, build a new, filtered collection.
    • (2) Don't iterate over the collection; instead, iterate over a copy of the collection
    • (2.5) For a dictionary, iterate over a copy of the keys, and fetch the values explicitly.

    Note that you're already fetching the values explicitly, despite iterating over the items, so there's no reason to go with #2 here.

    Here are implementations of the other two:

    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
    

    Or:

    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
    

    (If you want this to be Python 3 compatible, instead of img_dict.keys(), do img_dict.keys()[:].)

    So, how do you choose between the two?

    The first is generally easier to reason about—in general, immutable objects and pure operations are easy to reason about. For example, if you throw an exception somewhere, img_dict will always have the original version or the completed version, not something half-way in between. And of course you don't have to think through what it means to change something while iterating over it. However, in some rare cases, it's hard to transform your "delete everything where foo" algorithm into a "copy everything where not foo" algorithm.

    The first one is also usually much easier to rewrite as a comprehension (or a call to a higher-order function like filter), turn into a generator, refactor to pull out separate functions, etc.

    For performance, the first one will generally be faster and use less memory if you're filtering out many values, while the second will usually be better if you're keeping most values. (The cutoff is different for different collection types. As usually, it rarely matters, and if it does, you should write it both ways and profile.)

    Coming back to #0, I think it might apply in this case. You're walking through all of the keys to see if any are too old, to remove them. If you used, say, a sorted list, or a priority queue, you wouldn't have to do that. Now, if you need to use the collection as a dict more often than you need to flush the old values, you'd probably get more cost than benefit from changing the data structure. But why not have both? If you had a sorted list of keys, on top of the dictionary mapping keys to values, then you could just do this:

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

    Or, more simply:

    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]
    

    And you could wrap the sorted key list and the dictionary together into a nice Cache class or something.

    这篇关于如何从迭代的字典中删除一个项目?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆