【问题标题】:Remove an item from a dictionary when its key is unknown当它的键未知时从字典中删除一个项目
【发布时间】:2011-07-23 18:43:47
【问题描述】:

按值从字典中删除项目的最佳方法是什么,即当项目的键未知时?这是一个简单的方法:

for key, item in some_dict.items():
    if item is item_to_remove:
        del some_dict[key]

有没有更好的方法?迭代时从字典中改变(删除项目)有什么问题吗?

【问题讨论】:

标签: python dictionary


【解决方案1】:

请注意,您当前正在测试对象身份(is 仅在两个操作数由内存中的同一个对象表示时才返回 True - 这并不总是与两个对象比较等于 @987654327 @)。如果您是故意这样做的,那么您可以将代码重写为

some_dict = {key: value for key, value in some_dict.items() 
             if value is not value_to_remove}

但这可能不是你想要的:

>>> some_dict = {1: "Hello", 2: "Goodbye", 3: "You say yes", 4: "I say no"}
>>> value_to_remove = "You say yes"
>>> some_dict = {key: value for key, value in some_dict.items() if value is not value_to_remove}
>>> some_dict
{1: 'Hello', 2: 'Goodbye', 3: 'You say yes', 4: 'I say no'}
>>> some_dict = {key: value for key, value in some_dict.items() if value != value_to_remove}
>>> some_dict
{1: 'Hello', 2: 'Goodbye', 4: 'I say no'}

所以你可能想要!= 而不是is not

【讨论】:

  • 这是字典压缩吗?什么时候添加的?
  • 您可以在此处使用 some_dict.iteritems() 并将 forif 语句放在单独的行中以提高可读性
  • 我相信字典理解是在 Python 2.7 中添加的。
  • @J.F. Sebastian:我在 Python 3 上,iteritems 现在是 items。在 Python 2.7 中,iteritems() 确实更好。
  • @Buttons840 它们被称为dict comprehensions in PEP 274dictionary displays。正如 PEP 所说,他们是 added in 2.7 作为向后移植的 3.x 壮举。或者,您可以使用适当的生成器表达式(即 2.4)提供 dict()。 meta: 可以browse the peps here 查找资料。
【解决方案2】:

items() 返回一个列表,而您正在迭代的正是该列表,因此在这里改变循环中的 dict 并不重要。如果您改用iteritems(),则在循环would be problematic 中对dict 进行变异,对于Python 2.7 中的viewitems() 也是如此。

我想不出更好的方法来按值从字典中删除项目。

【讨论】:

    【解决方案3】:

    按照您的建议,在迭代时从字典中删除项目没有任何问题。注意多个线程同时使用同一个字典,可能会导致 KeyError 或其他问题。

    当然,请参阅http://docs.python.org/library/stdtypes.html#typesmapping 的文档

    【讨论】:

    • for k,v in d.iteritems(): del d[k] 会给出RuntimeError: dictionary changed size during iteration。请参阅 mithrandi 的解释。
    • 当然,d.iteritems() 不是原始海报的迭代方式,也不是我在回答中所指的内容。
    【解决方案4】:

    dict.pop(key[, default]) 方法允许您在知道密钥时删除项目。如果删除项目,则返回键处的值,否则返回作为default 传递的内容。见the docs。'

    例子:

    >>> dic = {'a':1, 'b':2}
    >>> dic
    {'a': 1, 'b': 2}
    >>> dic.pop('c', 0)
    0
    >>> dic.pop('a', 0)
    1
    >>> dic
    {'b': 2}
    

    【讨论】:

    • OP 询问何时密钥未知
    【解决方案5】:
    a = {'name': 'your_name','class': 4}
    if 'name' in a: del a['name']
    

    【讨论】:

    • OP 询问何时密钥未知。此答案假定密钥是已知的。
    【解决方案6】:

    我会建立一个需要删除的键列表,然后删除它们。它简单、高效,避免了同时迭代和改变字典的任何问题。

    keys_to_remove = [key for key, value in some_dict.iteritems()
                      if value == value_to_remove]
    for key in keys_to_remove:
        del some_dict[key]
    

    【讨论】:

    • OP 询问何时密钥未知。此答案假定密钥是已知的。
    【解决方案7】:

    delpop()的简单对比:

    import timeit
    code = """
    results = {'A': 1, 'B': 2, 'C': 3}
    del results['A']
    del results['B']
    """
    print timeit.timeit(code, number=100000)
    code = """
    results = {'A': 1, 'B': 2, 'C': 3}
    results.pop('A')
    results.pop('B')
    """
    print timeit.timeit(code, number=100000)
    

    结果:

    0.0329667857143
    0.0451040902256
    

    所以,delpop() 快。

    【讨论】:

    • 但是,性能差异并不大,如果您想避免引发异常,您可以向pop() 提供第二个参数(就像上面的@n-1-1 所做的那样)-不是del 运算符的选项。
    • 这个问题的辅助,但我也一直在努力理解timeit。感谢您提供这个清晰的示例。
    • OP 询问何时密钥未知。此答案假定密钥是已知的。
    【解决方案8】:
    y={'username':'admin','machine':['a','b','c']}
    if 'c' in y['machine'] : del y['machine'][y['machine'].index('c')]
    

    【讨论】:

      【解决方案9】:

      c 是新字典,a 是你原来的字典,{'z','w'} 是您要从 a 中删除的键

      c = {key:a[key] for key in a.keys() - {'z', 'w'}}
      

      同时检查:https://www.safaribooksonline.com/library/view/python-cookbook-3rd/9781449357337/ch01.html

      【讨论】:

        【解决方案10】:

        这就是我的做法。

        for key in some_dict.keys():
            if some_dict[key] == item_to_remove:
                some_dict.pop(key)
                break
        

        【讨论】:

          猜你喜欢
          • 2017-05-02
          • 1970-01-01
          • 2023-03-10
          • 2016-07-03
          • 2013-03-01
          • 1970-01-01
          • 2022-08-08
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多