【问题标题】:What is the best way to remove a dictionary item by value in python? [duplicate]在python中按值删除字典项的最佳方法是什么? [复制]
【发布时间】:2015-05-26 22:40:33
【问题描述】:

我想知道是否有 simple 方法可以从 python 字典 按值删除 onemore 字典元素.

我们有一本名为myDict的字典:

myDict = {1:"egg", "Answer":42, 8:14, "foo":42}

想要移除所有等于42的项目。

实施建议:

  1. 获取myDict中具有特定值的所有键的列表
    (例如参见get key by value in dictionary。)

  2. myDict中删除这个或多个dict元素(基于找到的键)
    (有关详细信息,请参阅Delete an element from a dictionary。)

那么,你认为现在用 Python 实现这个问题的最优雅最“pythonic”的方式是什么?

【问题讨论】:

  • “获取 first ... myDict 中值的键”的愿望有点可疑,@elegent,作为 first 的概念i> 并不真正适用于字典。
  • @user1656850:是的,你完全正确!非常感谢您指出这一点。我更新了问题:)

标签: python python-2.7 python-3.x dictionary


【解决方案1】:

你可以使用简单的dict理解:

myDict = {key:val for key, val in myDict.items() if val != 42}

这样:

>>> {key:val for key, val in myDict.items() if val != 42}
{8: 14, 1: 'egg'}

【讨论】:

  • 我不会将其命名为item, key,而是将其命名为key, val,并使用val != 42,因为它在语义上更正确。
  • 感谢您的回答! dict-comprehension 是个好主意,但在我看来,问题是关于如何从字典中删除项目。我知道我们只需要将推导的结果字典分配给myDict:myDict = {key:val for key, val in myDict.items() if val != 42},所以如果您方便,请更改您的答案。
【解决方案2】:

您必须创建一个副本以进行迭代,因为在循环内更改字典的大小会导致 RunTimeError。使用 items() 遍历字典副本中的键、值对,并将每个值与您要查找的值进行比较。如果匹配,则从字典中删除该键。

    for key, value in dict(myDict).items():
        if value == 42:
            del mydict[key]

在下面的 cmets 中添加问题的答案,因为它太大而无法发表评论。这是一个快速控制台会话,显示 mydict.copy()dict(myDict) 完成相同的事情。

>>>import copy
>>>dict1 = {1:"egg", "Answer":42, 8:14, "foo":42}
>>>dict2 = dict(dict1)
>>>dict3 = dict1.copy()
>>>dict4 = dict1
>>>dict1[1] = "egg sandwich"
>>>dict1
{'Answer': 42, 1: 'egg sandwich', 'foo': 42, 8: 14}
>>>dict2
{'Answer': 42, 1: 'egg', 'foo': 42, 8: 14}
>>>dict3
{'Answer': 42, 1: 'egg', 'foo': 42, 8: 14}
>>>dict4
{'Answer': 42, 1: 'egg sandwich', 'foo': 42, 8: 14}
>>>dict2['foo'] = "I pity the"
dict1
>>>{'Answer': 42, 1: 'egg sandwich', 'foo': 42, 8: 14}
>>>dict2
{'Answer': 42, 1: 'egg', 'foo': 'I pity the', 8: 14}
>>>dict3
{'Answer': 42, 1: 'egg', 'foo': 42, 8: 14}
>>>dict4
{'Answer': 42, 1: 'egg sandwich', 'foo': 42, 8: 14}
>>>dict4[8] = "new"
>>>dict1
{'Answer': 42, 1: 'egg sandwich', 'foo': 42, 8: 'new'}
>>>dict2
{'Answer': 42, 1: 'egg', 'foo': 'I pity the', 8: 14}
>>>dict3
{'Answer': 42, 1: 'egg', 'foo': 42, 8: 14}
>>>dict4
{'Answer': 42, 1: 'egg sandwich', 'foo': 42, 8: 'new'}
`

【讨论】:

  • myDict.copy() 效率更高
  • 我同意。感谢您指出了这一点。这也可以工作并消除在循环之前创建副本的额外行:for key, value in dict(myDict).items():
  • @cruane:非常感谢您的回答!也许你可以根据你的命令编辑你的答案。
  • 很高兴我能帮上忙。我将编辑答案以反映更改。
  • @PadraicCunningham:myDict.copy()dict(myDict) 有什么区别?
【解决方案3】:

您可以遍历副本并进行查找:

for k in myDict.copy():
    if myDict[k] == 42:
        del myDict[k]

或者只复制密钥:

myDict = {1:"egg", "Answer":42, 8:14, "foo":42}
for k in list(myDict):
    if myDict[k] == 42:
        del myDict[k]
print(myDict)
{8: 14, 1: 'egg'}

如果你想改变原始字典,那应该是最有效的。

【讨论】:

  • 谢谢!为什么要使用reversed() 来反转键列表?元素(即键和值对)未在字典中排序,因此在我看来更改顺序是不必要的步骤。
  • @elegent,试试不倒车,你会看到
  • ...它有效! :) 顺便说一句,你不需要 3 个右括号...
  • @elegent,是的,一个错字。是的,实际上 list(dict) 将适用于 python2 和 3
  • 好的,没问题,谢谢您的回答。我只是有点困惑。 :)
【解决方案4】:

我喜欢遵循“命中列表”方法,您可以遍历字典,然后将要删除的内容添加到列表中,然后在迭代后从该列表中删除条目,如下所示:

命中列表 =[] for dictEntry: if test condition, hitList.append

在 hitList 中的条目: 删除字典[条目]

这只是一些伪代码,但我过去已经成功了

【讨论】:

  • 我也更喜欢这种方法,因为不需要复制。它也适用于列表,只需存储索引,然后删除相应的元素,但首先从最高索引开始。
【解决方案5】:

使用字典理解。

如果您需要副本,请使用iteritems()

>>> {k:v for k, v in myDict.iteritems() if v!=42}
{8: 14, 1: 'egg'}

如果您不需要字典副本,您可以使用viewitems()

>>> {k:v for k, v in myDict.viewitems() if v!=42}
{8: 14, 1: 'egg'}

【讨论】:

  • 请对不赞成票发表评论,以便我改进答案。
  • 谢谢!在 Python 3.x 中,我们只使用 .items() 而不是 .iteritems()viewitems()?
  • 是的,python 3.x 和 2.x 存在差异,但是您的问题没有标记为 python 版本,所以我假设您正在寻找 2.x 解决方案。
  • 是的,对不起,你是对的。如果您方便,您可以将这些额外信息添加到您的答案中,这样我们就可以看到两个 Python 版本之间的区别。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-31
  • 1970-01-01
  • 1970-01-01
  • 2010-12-17
  • 2011-10-03
相关资源
最近更新 更多