如何在Python中从字典中删除项目?
在不修改原始词典的情况下,如何获取删除了该项的另一个词典?
如何在Python中从字典中删除项目?
在不修改原始词典的情况下,如何获取删除了该项的另一个词典?
当前回答
有很多不错的答案,但我想强调一点。
您可以使用dict.pop()方法和更通用的del语句从字典中删除项。它们都会对原始词典进行变异,因此您需要制作一份副本(详见下文)。
如果你提供给他们的密钥不在字典中,他们两个都会引发KeyError:
key_to_remove = "c"
d = {"a": 1, "b": 2}
del d[key_to_remove] # Raises `KeyError: 'c'`
and
key_to_remove = "c"
d = {"a": 1, "b": 2}
d.pop(key_to_remove) # Raises `KeyError: 'c'`
你必须注意这一点:
通过捕获异常:
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)
and
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)
通过执行检查:
key_to_remove = "c"
d = {"a": 1, "b": 2}
if key_to_remove in d:
del d[key_to_remove]
and
key_to_remove = "c"
d = {"a": 1, "b": 2}
if key_to_remove in d:
d.pop(key_to_remove)
但使用pop()还有一种更简洁的方法-提供默认返回值:
key_to_remove = "c"
d = {"a": 1, "b": 2}
d.pop(key_to_remove, None) # No `KeyError` here
除非您使用pop()获取要删除的键的值,否则您可以提供任何内容,而不是必需的None。尽管在check中使用del可能会稍微快一些,因为pop()是一个函数,其自身的复杂性会导致开销。通常情况并非如此,因此使用默认值的pop()就足够了。
至于主要问题,你必须复制你的字典,保存原来的字典,并在不删除密钥的情况下创建一个新字典。
这里的一些其他人建议使用copy.deepcopy()制作一个完整(深度)副本,这可能是一种过度的复制,使用copy.copy()或dict.copy()制作“普通”(浅)副本就足够了。字典保留对对象的引用作为键的值。因此,当您从字典中删除键时,将删除该引用,而不是被引用的对象。如果内存中没有其他对象的引用,则垃圾收集器稍后会自动删除对象本身。与浅拷贝相比,制作深度拷贝需要更多的计算,因此它通过制作拷贝、浪费内存和向GC提供更多的工作来降低代码性能,有时浅拷贝就足够了。
但是,如果您将可变对象作为字典值,并计划稍后在返回的字典中修改它们而不使用键,则必须进行深度复制。
使用浅拷贝:
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}
使用深度副本:
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}
其他回答
我认为你的解决方案是最好的方法。但如果你想要另一个解决方案,你可以使用旧字典中的关键字创建一个新字典,而不包括你指定的关键字,如下所示:
>>> 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'}
…我如何从字典中删除项目以返回副本(即不修改原件)?
dict是用于此目的的错误数据结构。
当然,复制字典并从副本中弹出是有效的,建立一个新的字典并理解它也是有效的,但是所有的复制都需要时间,你已经用线性时间操作代替了恒定时间操作。并且所有这些活动副本一次占用每个副本的空间线性空间。
其他数据结构,如哈希数组映射尝试,正是为这种用例而设计的:添加或删除元素会在对数时间内返回副本,并与原始元素共享大部分存储空间。1
当然,也有一些缺点。性能是对数而不是常数(尽管基数较大,通常为32-128)。而且,虽然可以使非变异API与dict相同,但“变异”API明显不同。最重要的是,Python中没有HAMT电池。2
pyristent库是Python的基于HAMT的dict替换(以及各种其他类型)的一个非常可靠的实现。它甚至有一个漂亮的evolver API,用于将现有的变异代码尽可能平滑地移植到持久代码。但如果你想明确地返回拷贝而不是变异,你可以这样使用:
>>> 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})
d3=d1.remove('a')正是问题所要求的。
如果您在pmap中嵌入了dict和list等可变数据结构,那么仍然会存在别名问题,您只能通过一直保持不变,嵌入pmap和pvectors来解决这个问题。
1.HAMT在Scala、Clojure、Haskell等语言中也很流行,因为它们在无锁编程和软件事务内存方面表现得很好,但这两者在Python中都不太相关。
2.事实上,stdlib中有一个HAMT,用于contextvars的实现。先前撤回的政治公众人物解释了原因。但这是库的隐藏实现细节,而不是公共集合类型。
del陈述就是你要找的。如果您有一个名为foo的字典,其键名为“bar”,则可以像这样从foo中删除“bar”:
del foo['bar']
请注意,这将永久修改正在操作的词典。如果您想保留原始词典,则必须事先创建一个副本:
>>> foo = {'bar': 'baz'}
>>> fu = dict(foo)
>>> del foo['bar']
>>> print foo
{}
>>> print fu
{'bar': 'baz'}
dict调用生成一个浅显的副本。如果需要深度复制,请使用copy.depcopy。
为了方便,您可以复制并粘贴以下方法:
def minus_key(key, dictionary):
shallow_copy = dict(dictionary)
del shallow_copy[key]
return shallow_copy
没有,除了
def dictMinus(dct, val):
copy = dct.copy()
del copy[val]
return copy
然而,通常只创建稍微修改过的字典的副本可能不是一个好主意,因为这会导致相对较大的内存需求。通常最好记录旧字典(如果需要),然后修改它。
species = {'HI': {'1': (1215.671, 0.41600000000000004),
'10': (919.351, 0.0012),
'1025': (1025.722, 0.0791),
'11': (918.129, 0.0009199999999999999),
'12': (917.181, 0.000723),
'1215': (1215.671, 0.41600000000000004),
'13': (916.429, 0.0005769999999999999),
'14': (915.824, 0.000468),
'15': (915.329, 0.00038500000000000003),
'CII': {'1036': (1036.3367, 0.11900000000000001), '1334': (1334.532, 0.129)}}
以下代码将复制dict物种并删除不在trans_HI中的项目
trans_HI=['1025','1215']
for transition in species['HI'].copy().keys():
if transition not in trans_HI:
species['HI'].pop(transition)