关于python:从字典中删除元素

Delete an element from a dictionary

有没有办法从python的字典中删除一个条目?

此外,如何从字典中删除项目以返回副本(即,不修改原件)?


del语句删除一个元素:

1
del d[key]

但是,这会改变现有词典,因此词典的内容会为引用同一实例的任何其他人而更改。要返回新词典,请复制词典:

1
2
3
4
def removekey(d, key):
    r = dict(d)
    del r[key]
    return r

dict()构造函数生成一个简单的副本。要进行深度复制,请参阅copy模块。

请注意,为每一个dict制作一个副本del/assignment/etc.意味着您将从固定时间变为线性时间,也将使用线性空间。对于小口述,这不是问题。但是,如果您计划制作大量大型听写的副本,您可能需要不同的数据结构,如HAMT(如本答案中所述)。


pop使字典变异。

1
2
3
4
5
 >>>lol = {"hello":"gdbye
<div class="
suo-content">[collapse title=""]<ul><li>也适用于<wyn>lambda</wyn>(而<wyn>del</wyn>不适用)。</li><li>"del"还行,但"pop"在我看来更像是"Python"。</li><li>@伊万利昂茨为什么?</li><li><wyn>pop</wyn>返回"popped"的值,允许您出于任何进一步的原因使用该值。如果不是更多的"Python",我会说这似乎更好,当然:)。它不是一个dict,但对这两者的工作方式相同:github.com/ivanlmj/python-prototypes/blob/master/3.4/&hellip;</li></ul>[/collapse]</div><p><center>[wp_ad_camp_1]</center></p><hr><P>我认为你的解决方案是最好的方法。但是,如果需要其他解决方案,可以使用旧字典中的键创建新字典,而不包括指定的键,如下所示:</P>[cc lang="python"]>>> a
{0: 'zero', 1: 'one', 2: 'two', 3: 'three'}
>>> {i:a[i] for i in a if i!=0}
{1: 'one', 2: 'two', 3: 'three'}


del语句就是您要查找的内容。如果您有一个名为foo的字典,其中有一个名为"bar"的键,则可以从foo中删除"bar",如下所示:

1
del foo['bar']

请注意,这将永久修改正在操作的字典。如果您想保留原始词典,必须事先创建一份副本:

1
2
3
4
5
6
7
>>> foo = {'bar': 'baz'}
>>> fu = dict(foo)
>>> del foo['bar']
>>> print foo
{}
>>> print fu
{'bar': 'baz'}

dict的调用只是一个简单的复制。如果您需要一份深度拷贝,请使用copy.deepcopy

为了方便起见,您可以复制和粘贴以下方法:

1
2
3
4
def minus_key(key, dictionary):
    shallow_copy = dict(dictionary)
    del shallow_copy[key]
    return shallow_copy


有很多不错的答案,但我想强调一件事。

您可以使用dict.pop()方法和更通用的del语句从字典中删除项。它们都会改变原来的词典,因此您需要复制一份(请参阅下面的详细信息)。

如果你提供给他们的密钥不在字典中,他们两个都会提出一个KeyError

1
2
3
key_to_remove ="c"
d = {"a": 1,"b": 2}
del d[key_to_remove]  # Raises `KeyError: 'c'`

1
2
3
key_to_remove ="c"
d = {"a": 1,"b": 2}
d.pop(key_to_remove)  # Raises `KeyError: 'c'`

你必须处理好这件事:

通过捕获异常:

1
2
3
4
5
6
key_to_remove ="c"
d = {"a": 1,"b": 2}
try:
    del d[key_to_remove]
except KeyError as ex:
    print("No such key: '%s'" % ex.message)

1
2
3
4
5
6
key_to_remove ="c"
d = {"a": 1,"b": 2}
try:
    d.pop(key_to_remove)
except KeyError as ex:
    print("No such key: '%s'" % ex.message)

通过执行检查:

1
2
3
4
key_to_remove ="c"
d = {"a": 1,"b": 2}
if key_to_remove in d:
    del d[key_to_remove]

1
2
3
4
key_to_remove ="c"
d = {"a": 1,"b": 2}
if key_to_remove in d:
    d.pop(key_to_remove)

但是对于pop(),还有一种更简洁的方法——提供默认返回值:

1
2
3
key_to_remove ="c"
d = {"a": 1,"b": 2}
d.pop(key_to_remove, None)  # No `KeyError` here

除非您使用pop()获取要删除的密钥的值,否则您可以提供任何不必要的None。虽然使用delin检查可能会稍微快一些,因为pop()是一种功能,其自身的并发症会导致开销。通常情况并非如此,所以使用缺省值的pop()就足够了。

至于主要问题,你必须复制你的字典,保存原来的字典,并且在不取下键的情况下换一个新字典。

这里的一些人建议用copy.deepcopy()制作一份完整的(深度)拷贝,这可能是一种过度杀戮,用copy.copy()dict.copy()制作一份"普通"(浅)拷贝就足够了。字典将对象的引用作为键的值保存。因此,从字典中删除键时,将删除此引用,而不是要引用的对象。如果内存中没有其他对象的引用,垃圾收集器稍后可以自动删除对象本身。与浅拷贝相比,进行深拷贝需要更多的计算,因此通过进行拷贝、浪费内存和向GC提供更多的工作来降低代码性能,有时浅拷贝就足够了。

但是,如果您将可变对象作为字典值,并计划稍后在返回的字典中修改它们,而不使用键,则必须进行深度复制。

浅拷贝:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def get_dict_wo_key(dictionary, key):
   """Returns a **shallow** copy of the dictionary without a key."""
    _dict = dictionary.copy()
    _dict.pop(key, None)
    return _dict


d = {"a": [1, 2, 3],"b": 2,"c": 3}
key_to_remove ="c"

new_d = get_dict_wo_key(d, key_to_remove)
print(d)  # {"a": [1, 2, 3],"b": 2,"c": 3}
print(new_d)  # {"a": [1, 2, 3],"b": 2}
new_d["a"].append(100)
print(d)  # {"a": [1, 2, 3, 100],"b": 2,"c": 3}
print(new_d)  # {"a": [1, 2, 3, 100],"b": 2}
new_d["b"] = 2222
print(d)  # {"a": [1, 2, 3, 100],"b": 2,"c": 3}
print(new_d)  # {"a": [1, 2, 3, 100],"b": 2222}

深拷贝:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from copy import deepcopy


def get_dict_wo_key(dictionary, key):
   """Returns a **deep** copy of the dictionary without a key."""
    _dict = deepcopy(dictionary)
    _dict.pop(key, None)
    return _dict


d = {"a": [1, 2, 3],"b": 2,"c": 3}
key_to_remove ="c"

new_d = get_dict_wo_key(d, key_to_remove)
print(d)  # {"a": [1, 2, 3],"b": 2,"c": 3}
print(new_d)  # {"a": [1, 2, 3],"b": 2}
new_d["a"].append(100)
print(d)  # {"a": [1, 2, 3],"b": 2,"c": 3}
print(new_d)  # {"a": [1, 2, 3, 100],"b": 2}
new_d["b"] = 2222
print(d)  # {"a": [1, 2, 3],"b": 2,"c": 3}
print(new_d)  # {"a": [1, 2, 3, 100],"b": 2222}

1
2
3
d = {1: 2, '2': 3, 5: 7}
del d[5]
print 'd = ', d

结果:d = {1: 2, '2': 3}


… how can I delete an item from a dictionary to return a copy (i.e., not modifying the original)?

dict是用于此目的的错误数据结构。

当然,复制听写和从复制中弹出都是有效的,构建一个理解力强的新听写也是有效的,但是所有的复制都需要时间,你已经用一个线性时间操作替换了一个固定时间操作。所有这些活拷贝一次就占用空间线性空间。

其他的数据结构,比如散列数组映射尝试,都是为这种用例而设计的:添加或删除一个元素会以对数时间返回一个副本,并与原始元素共享其大部分存储空间。1

当然也有一些缺点。性能是对数的,而不是常量(虽然底数很大,通常为32-128)。而且,虽然您可以使非变异API与dict相同,但"变异"API明显不同。而且,最重要的是,python中没有包含hamt电池。

pyrsistent库是基于hamt的dict替换(以及各种其他类型)的python非常可靠的实现。它甚至还有一个漂亮的Evolver API,可以将现有的可变代码尽可能顺利地移植到持久代码中。但是,如果您想明确地返回副本而不是改变副本,您只需这样使用它:

1
2
3
4
5
6
7
8
9
10
>>> from pyrsistent import m
>>> d1 = m(a=1, b=2)
>>> d2 = d1.set('c', 3)
>>> d3 = d1.remove('a')
>>> d1
pmap({'a': 1, 'b': 2})
>>> d2
pmap({'c': 3, 'a': 1, 'b': 2})
>>> d3
pmap({'b': 2})

这正是问题所在。

如果在pmap中嵌入了dictlist这样的可变数据结构,那么仍然存在混叠问题,只能通过一直保持不变、嵌入pmappvector来解决。

>1。HAMTs在scala、clojure、haskell等语言中也很流行,因为它们非常适合无锁编程和软件事务性内存,但这两种语言在python中都不是非常相关的。

>2。实际上,stdlib中有一个hamt,用于contextvars的实现。早些时候退出的政治公众人物解释了原因。但这是库的隐藏实现细节,而不是公共集合类型。


Simply call del d['key'].

However, in production, it is always a good practice to check if 'key' exists in d.

1
2
if 'key' in d:
    del d['key']


不,除了

1
2
3
4
def dictMinus(dct, val):
   copy = dct.copy()
   del copy[val]
   return copy

然而,通常只创建稍微改动过的字典的副本可能不是一个好主意,因为这样会导致相对较大的内存需求。通常最好先记录旧字典(如果必要的话),然后再修改它。


1
2
3
4
5
6
7
8
>>> def delete_key(dict, key):
...     del dict[key]
...     return dict
...
>>> test_dict = {'one': 1, 'two' : 2}
>>> print delete_key(test_dict, 'two')
{'one': 1}
>>>

这不做任何错误处理,它假定密钥在dict中,您可能要检查first和raise,如果它不是


这里是顶层设计方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
def eraseElement(d,k):
    if isinstance(d, dict):
        if k in d:
            d.pop(k)
            print(d)
        else:
            print("Cannot find matching key")
    else:
        print("Not able to delete")


exp = {'A':34, 'B':55, 'C':87}
eraseElement(exp, 'C')

我正在将字典和我想要的键传递到我的函数中,验证它是否是字典,以及键是否正常,如果两者都存在,则从字典中删除值并打印出剩余部分。

输出:{'B': 55, 'A': 34}

希望有帮助!


下面的代码片段将绝对帮助您,我在每行中添加了注释,这将帮助您理解代码。

1
2
3
4
5
6
7
8
9
10
11
def execute():
   dic = {'a':1,'b':2}
   dic2 = remove_key_from_dict(dic, 'b')  
   print(dict2)           # {'a': 1}
   print(dict)            # {'a':1,'b':2}

def remove_key_from_dict(dictionary_to_use, key_to_delete):
   copy_of_dict = dict(dictionary_to_use)     # creating clone/copy of the dictionary
   if key_to_delete in copy_of_dict :         # checking given key is present in the dictionary
       del copy_of_dict [key_to_delete]       # deleting the key from the dictionary
   return copy_of_dict                        # returning the final dictionary

也可以使用dict.pop()。

1
2
3
4
d = {"a": 1,"b": 2}

res = d.pop("c")  # No `KeyError` here
print (res)       # this line will not execute

或者更好的方法是

1
2
3
4
5
6
7
res = d.pop("c","key not found")
print (res)   # key not found
print (d)     # {"a": 1,"b": 2}

res = d.pop("b","key not found")
print (res)   # 2
print (d)     # {"a": 1}

很好的一行代码,用于检查密钥是否存在、删除它、返回值或默认值:

1
ret_val = ('key' in body and body.pop('key')) or 5


下面是另一个使用列表理解的变体:

1
2
3
original_d = {'a': None, 'b': 'Some'}
d = dict((k,v) for k, v in original_d.iteritems() if v)
# result should be {'b': 'Some'}

该方法基于本帖的答案:从dict中删除带有空字符串的键的有效方法