Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/opengl/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scripting 如何在迭代字典时从字典中删除项目?_Scripting_Dictionary_Python - Fatal编程技术网

Scripting 如何在迭代字典时从字典中删除项目?

Scripting 如何在迭代字典时从字典中删除项目?,scripting,dictionary,python,Scripting,Dictionary,Python,在Python中迭代字典时从字典中删除条目是否合法 例如: for k, v in mydict.iteritems(): if k == val: del mydict[k] 其思想是从字典中删除不满足特定条件的元素,而不是创建一个新字典,它是被迭代字典的子集 这是一个好的解决方案吗?还有更优雅/高效的方法吗?迭代一个副本,例如items()返回的副本: 您不能在迭代集合时对其进行修改。这种方式是疯狂的——最值得注意的是,如果允许您删除并删除当前项,迭代器将不得不继续(+1)

在Python中迭代字典时从字典中删除条目是否合法

例如:

for k, v in mydict.iteritems():
   if k == val:
     del mydict[k]
其思想是从字典中删除不满足特定条件的元素,而不是创建一个新字典,它是被迭代字典的子集


这是一个好的解决方案吗?还有更优雅/高效的方法吗?

迭代一个副本,例如
items()
返回的副本:


您不能在迭代集合时对其进行修改。这种方式是疯狂的——最值得注意的是,如果允许您删除并删除当前项,迭代器将不得不继续(+1),对
next
的下一次调用将超出(+2),因此您将跳过一个元素(即您删除的元素后面的元素)。您有两个选择:

  • 复制所有键(或值,或两者,取决于需要),然后迭代这些键。您可以为此使用
    .keys()
    等(在Python3中,将生成的迭代器传递给
    列表
    )。但在空间方面可能会非常浪费
  • 像往常一样迭代
    mydict
    ,将要删除的键保存在一个单独的集合
    中,以_delete
    。迭代完
    mydict
    后,删除
    中的所有项目,以从
    mydict
    中删除
    。在第一种方法上节省一些空间(取决于删除了多少关键点和保留了多少关键点),但还需要多行
编辑:

这个答案对Python3不起作用,并且会给出一个
运行时错误

运行时错误:字典在迭代期间更改了大小

这是因为
mydict.keys()
返回的是迭代器而不是列表。 正如注释中所指出的,只需通过
list(mydict.keys())
mydict.keys()转换为一个列表就可以了


控制台中的一个简单测试表明,在对字典进行迭代时无法修改它:

>>> mydict = {'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> for k, v in mydict.iteritems():
...    if k == 'two':
...        del mydict[k]
...
------------------------------------------------------------
Traceback (most recent call last):
  File "<ipython console>", line 1, in <module>
RuntimeError: dictionary changed size during iteration
如果需要根据items值进行删除,请改用
items()
方法:

>>> for k, v in mydict.items():
...     if v == 3:
...         del mydict[k]
...
>>> mydict
{'four': 4, 'one': 1}

您还可以通过两个步骤完成:

remove = [k for k in mydict if k == val]
for k in remove: del mydict[k]
我最喜欢的方法通常是做一个新的口述:

# Python 2.7 and 3.x
mydict = { k:v for k,v in mydict.items() if k!=val }
# before Python 2.7
mydict = dict((k,v) for k,v in mydict.iteritems() if k!=val)

对于python3,在dic.keys()上迭代将引发字典大小错误。您可以使用以下替代方法:

通过python3测试,它工作正常,并且不会出现错误“字典在迭代过程中更改了大小”

my_dic = { 1:10, 2:20, 3:30 }
# Is important here to cast because ".keys()" method returns a dict_keys object.
key_list = list( my_dic.keys() )

# Iterate on the list:
for k in key_list:
    print(key_list)
    print(my_dic)
    del( my_dic[k] )


print( my_dic )
# {}

您可以首先构建一个要删除的键列表,然后迭代该列表以删除它们

dict = {'one' : 1, 'two' : 2, 'three' : 3, 'four' : 4}
delete = []
for k,v in dict.items():
    if v%2 == 1:
        delete.append(k)
for i in delete:
    del dict[i]

你可以用字典来理解


d={k:d[k]表示d中的k,如果d[k]!=val}
使用
列表(mydict)
最干净:

>>> mydict = {'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> for k in list(mydict):
...     if k == 'three':
...         del mydict[k]
... 
>>> mydict
{'four': 4, 'two': 2, 'one': 1}
这对应于列表的并行结构:

>>> mylist = ['one', 'two', 'three', 'four']
>>> for k in list(mylist):                            # or mylist[:]
...     if k == 'three':
...         mylist.remove(k)
... 
>>> mylist
['one', 'two', 'four']

这两种方法都适用于python2和python3。

我在python3中尝试了上述解决方案,但在dict中存储对象时,这似乎是唯一适用于我的方法。基本上,您可以复制dict()并在删除原始词典中的条目时对其进行迭代

        tmpDict = realDict.copy()
        for key, value in tmpDict.items():
            if value:
                del(realDict[key])

如果要删除的项目总是在dict迭代的“开始”,那么有一种方法可能是合适的

而mydict:
key,value=next(iter(mydict.items())
如果应删除(键、值):
德尔米迪克特[钥匙]
其他:
打破
“开始”仅保证在某些Python版本/实现中保持一致。例如来自

dict对象的插入顺序保留性质已被声明为Python语言规范的正式部分


这种方法避免了许多其他答案所建议的dict的副本,至少在Python 3中是这样。

@senderle:事实上,从2.7开始;幸运的是,这些值至少不会被深度复制,只是被链接。但是如果你有很多钥匙,可能会很糟糕。出于这个原因,我更喜欢
remove
循环方法。您还可以组合以下步骤:
For k in[k For k in mydict if k==val]:del mydict[k]
到目前为止,第一种解决方案是该线程中唯一一种有效的大型dicts解决方案,因为它不会生成完整的副本。这没有多大意义——那么你不能直接
del v
,因此你已经为每个v创建了一个你永远不会使用的副本,并且你必须通过键访问这些项
dict.keys()
是一个更好的选择。@Josh:这取决于您需要使用
v
作为删除标准的程度。在Python 3下,
dict.items()
返回一个迭代器,而不是一个副本。请参阅的注释,它(遗憾地)也采用Python 2语义。请注意,在Python 3中,dict.items()返回一个迭代器(dict.iteritems()不存在)。要详细说明@TimLesher注释。。。这在Python3中不起作用。为了详细说明@max的精化,如果您使用2to3转换上述代码,它将起作用。其中一个默认修复程序将使循环看起来像列表中k,v的
(mydict.items()):
这在Python 3中运行良好。对于
keys()
变成
list(keys())
,也一样。这不起作用。我得到一个错误:
RuntimeError:dictionary在迭代过程中改变了大小
@TomášZato正如沃尔特指出的,对于python3,您需要对列表中的k(mydict.keys())使用
,因为python3使keys()方法成为迭代器,并且在迭代过程中不允许删除dict项。通过添加list()调用,可以将keys()迭代器转换为列表。因此,当您处于for循环的主体中时,您不再重复字典本身。一个相关的问题,有非常有趣的答案:。您可以很容易地尝试。如果失败了,这是不合法的。@Triarion一号可以很容易地尝试。。。很容易就学到了没有价值的东西。如果它成功了,就不一定合法。边缘案例和意外警告比比皆是。这个问题对所有人来说都很重要
>>> mylist = ['one', 'two', 'three', 'four']
>>> for k in list(mylist):                            # or mylist[:]
...     if k == 'three':
...         mylist.remove(k)
... 
>>> mylist
['one', 'two', 'four']
        tmpDict = realDict.copy()
        for key, value in tmpDict.items():
            if value:
                del(realDict[key])