安全地从字典中删除多个键

时间:2012-01-24 23:05:52

标签: python dictionary

我知道要从我的字典d中删除一个条目'key',安全地执行:

if d.has_key('key'):
    del d['key']

但是,我需要安全地从字典中删除多个条目。我正在考虑在元组中定义条目,因为我需要多次执行此操作。

entitiesToREmove = ('a', 'b', 'c')
for x in entitiesToRemove:
    if d.has_key(x):
        del d[x]

但是,我想知道是否有更聪明的方法来做到这一点?

16 个答案:

答案 0 :(得分:182)

d = {'some':'data'}
entriesToRemove = ('any', 'iterable')
for k in entriesToRemove:
    d.pop(k, None)

答案 1 :(得分:72)

使用 Dict理解

final_dict = {key: t[key] for key in t if key not in [key1, key2]}

要删除 key1 key2

在下面的例子中,键“b”和“c”将被删除&它保存在按键列表中。

>>> a
{'a': 1, 'c': 3, 'b': 2, 'd': 4}
>>> keys = ["b", "c"]
>>> print {key: a[key] for key in a if key not in keys}
{'a': 1, 'd': 4}
>>> 

答案 2 :(得分:37)

为什么不喜欢这样:

entries = ('a', 'b', 'c')
the_dict = {'b': 'foo'}

def entries_to_remove(entries, the_dict):
    for key in entries:
        if key in the_dict:
            del the_dict[key]

mattbornski使用dict.pop()

提供了更紧凑的版本

答案 3 :(得分:17)

如果您还需要检索要删除的键的值,这将是一个非常好的方法:

valuesRemoved = [d.pop(k, None) for k in entitiesToRemove]

您当然可以仅仅为了从d删除密钥而执行此操作,但是您将不必要地使用列表推导创建值列表。对于函数的副作用,使用列表推导也有点不清楚。

答案 4 :(得分:15)

解决方案是使用mapfilter函数

python 2

d={"a":1,"b":2,"c":3}
l=("a","b","d")
map(d.__delitem__, filter(d.__contains__,l))
print(d)

python 3

d={"a":1,"b":2,"c":3}
l=("a","b","d")
list(map(d.__delitem__, filter(d.__contains__,l)))
print(d)

你得到:

{'c': 3}

答案 5 :(得分:4)

我对任何现有答案都没有任何问题,但我很惊讶没有找到这个解决方案:

keys_to_remove = ['a', 'b', 'c']
my_dict = {k: v for k, v in zip("a b c d e f g".split(' '), [0, 1, 2, 3, 4, 5, 6])}

for k in keys_to_remove:
    try:
        del my_dict[k]
    except KeyError:
        pass

assert my_dict == {'d': 3, 'e': 4, 'f': 5, 'g': 6}

注意:我偶然发现了来自here的这个问题。我的回答与this answer有关。

答案 6 :(得分:4)

对cpython 3的一些计时测试表明,简单的for循环是最快的方法,并且可读性强。添加函数也不会造成太多开销:

timeit结果(10000次迭代):

  • all(x.pop(v) for v in r) # 0.85
  • all(map(x.pop, r)) # 0.60
  • list(map(x.pop, r)) # 0.70
  • all(map(x.__delitem__, r)) # 0.44
  • del_all(x, r) # 0.40
  • <inline for loop>(x, r) # 0.35
def del_all(mapping, to_remove):
      """Remove list of elements from mapping."""
      for key in to_remove:
          del mapping[key]

对于小迭代,由于函数调用的开销,执行“内联”要快一些。但是del_all是不掉毛安全的,可重用的,并且比所有python理解和映射构造都快。

答案 7 :(得分:3)

找到了popmap的解决方案

d = {'a': 'valueA', 'b': 'valueB', 'c': 'valueC', 'd': 'valueD'}
keys = ['a', 'b', 'c']
list(map(d.pop, keys))
print(d)

此输出:

{'d': 'valueD'}

我这么晚回答了这个问题,只是因为我认为如果有人进行搜索,将来会有所帮助。这可能会有帮助。

更新

如果字典中不存在键,则以上代码将引发错误。

DICTIONARY = {'a': 'valueA', 'b': 'valueB', 'c': 'valueC', 'd': 'valueD'}
keys = ['a', 'l', 'c']

def remove_keys(key):
    try:
        DICTIONARY.pop(key, None)
    except:
        pass  # or do any action

list(map(remove_key, keys))
print(DICTIONARY)

输出:

DICTIONARY = {'b': 'valueB', 'd': 'valueD'}

答案 8 :(得分:2)

为什么不:

entriestoremove = (2,5,1)
for e in entriestoremove:
    if d.has_key(e):
        del d[e]

我不知道“更聪明的方式”是什么意思。当然还有其他方法,也许是字典理解:

entriestoremove = (2,5,1)
newdict = {x for x in d if x not in entriestoremove}

答案 9 :(得分:2)

<强>内联

import functools

#: not key(c) in d
d = {"a": "avalue", "b": "bvalue", "d": "dvalue"}

entitiesToREmove = ('a', 'b', 'c')

#: python2
map(lambda x: functools.partial(d.pop, x, None)(), entitiesToREmove)

#: python3

list(map(lambda x: functools.partial(d.pop, x, None)(), entitiesToREmove))

print(d)
# output: {'d': 'dvalue'}

答案 10 :(得分:1)

我已经测试了三种方法的性能:

# Method 1: `del`
for key in remove_keys:
    if key in d:
        del d[key]

# Method 2: `pop()`
for key in remove_keys:
    d.pop(key, None)

# Method 3: comprehension
{key: v for key, v in d.items() if key no in remove_keys}

这是一百万次迭代的结果:

  1. del:2.03s 2.0 ns / iter(100%)
  2. pop():2.38秒2.4 ns / iter(117%)
  3. 理解力:4.11s 4.1 ns / iter(202%)

因此delpop()都是最快的。理解速度要慢2倍。 但是无论如何,我们在这里说 nanoseconds :)Python中的字典非常快。

答案 11 :(得分:0)

如果您使用的是Python 3,我认为利用键可以被视为集合的事实是最好的方法。

def remove_keys(d, keys):
    to_remove = set(keys)
    filtered_keys = d.keys() - to_remove
    filtered_values = map(d.get, filtered_keys)
    return dict(zip(filtered_keys, filtered_values))

示例:

>>> remove_keys({'k1': 1, 'k3': 3}, ['k1', 'k2'])
{'k3': 3}

答案 12 :(得分:0)

最好完全支持字典的set方法(而不是我们在Python 3.9中遇到的麻烦),以便您可以简单地“删除”一组键。但是,只要不是这种情况,并且您有一个大型词典并且可能要删除大量键,则可能需要了解性能。因此,我创建了一些代码,该代码创建的大小足以进行有意义的比较:100,000 x 1000矩阵,因此总共10,000,00个项目。

from itertools import product
from time import perf_counter

# make a complete worksheet 100000 * 1000
start = perf_counter()
prod = product(range(1, 100000), range(1, 1000))
cells = {(x,y):x for x,y in prod}
print(len(cells))

print(f"Create time {perf_counter()-start:.2f}s")
clock = perf_counter()
# remove everything above row 50,000

keys = product(range(50000, 100000), range(1, 100))

# for x,y in keys:
#     del cells[x, y]

for n in map(cells.pop, keys):
    pass

print(len(cells))
stop = perf_counter()
print(f"Removal time {stop-clock:.2f}s")

1000万或更多的项目在某些情况下并不罕见。比较本地计算机上的这两种方法,我发现在使用mappop时有一些改进,大概是因为调用的函数较少,但是在我的计算机上都花费了大约2.5s。但是,与首先创建字典(55s)或在循环中包括检查所需的时间相比,这显得苍白。如果可能,那么最好创建一个集合,该集合是字典键和过滤器的交集:

keys = cells.keys() & keys

总而言之:del已经过优化,所以不用担心使用它。

答案 13 :(得分:0)

另一种从字典中删除键列表的 map() 方法

并避免引发 KeyError 异常

    dic = {
        'key1': 1,
        'key2': 2,
        'key3': 3,
        'key4': 4,
        'key5': 5,
    }
    
keys_to_remove = ['key_not_exist', 'key1', 'key2', 'key3']
k = list(map(dic.pop, keys_to_remove, keys_to_remove))

print('k=', k)
print('dic after =  \n', dic)

**this will produce output** 

k= ['key_not_exist', 1, 2, 3]
dic after =  {'key4': 4, 'key5': 5}

Duplicate keys_to_remove 是人为的,它需要为 dict.pop() 函数提供默认值。 你可以在这里添加任何数组 len_ = len(key_to_remove)


例如

dic = {
    'key1': 1,
    'key2': 2,
    'key3': 3,
    'key4': 4,
    'key5': 5,
}

keys_to_remove = ['key_not_exist', 'key1', 'key2', 'key3']    
k = list(map(dic.pop, keys_to_remove, np.zeros(len(keys_to_remove))))

print('k=', k)
print('dic after = ', dic)

** 将产生输出 **

k= [0.0, 1, 2, 3]
dic after =  {'key4': 4, 'key5': 5}

答案 14 :(得分:0)

def delete_keys_from_dict(dictionary, keys):
"""
Deletes the unwanted keys in the dictionary
:param dictionary: dict
:param keys: list of keys
:return: dict (modified)
"""
from collections.abc import MutableMapping

keys_set = set(keys)
modified_dict = {}
for key, value in dictionary.items():
    if key not in keys_set:
        if isinstance(value, list):
            modified_dict[key] = list()
            for x in value:
                if isinstance(x, MutableMapping):
                    modified_dict[key].append(delete_keys_from_dict(x, keys_set))
                else:
                    modified_dict[key].append(x)
        elif isinstance(value, MutableMapping):
            modified_dict[key] = delete_keys_from_dict(value, keys_set)
        else:
            modified_dict[key] = value
return modified_dict


_d = {'a': 1245, 'b': 1234325, 'c': {'a': 1245, 'b': 1234325}, 'd': 98765,
      'e': [{'a': 1245, 'b': 1234325},
            {'a': 1245, 'b': 1234325},
            {'t': 767}]}

_output = delete_keys_from_dict(_d, ['a', 'b'])
_expected = {'c': {}, 'd': 98765, 'e': [{}, {}, {'t': 767}]}
print(_expected)
print(_output)

答案 15 :(得分:-1)

我迟到了这个讨论,但对其他人来说。解决方案可能是创建一个密钥列表。

k = ['a','b','c','d']

然后在列表推导或for循环中使用pop()迭代键并一次弹出一个键。

new_dictionary = [dictionary.pop(x, 'n/a') for x in k]

如果密钥不存在,则“n / a”需要返回默认值。