我有一个字典,里面有一大堆词条。我只对其中的几个感兴趣。有什么简单的方法可以把其他的都剪掉吗?


当前回答

下面是在一行中使用del的另一个简单方法:

for key in e_keys: del your_dict[key]

E_keys是要排除的键的列表。它会更新你的字典,而不是给你一个新的。

如果你想要一个新的输出字典,那么在删除之前做一个字典的副本:

new_dict = your_dict.copy()           #Making copy of dict

for key in e_keys: del new_dict[key]

其他回答

代码1:

dict = { key: key * 10 for key in range(0, 100) }
d1 = {}
for key, value in dict.items():
    if key % 2 == 0:
        d1[key] = value

代码2:

dict = { key: key * 10 for key in range(0, 100) }
d2 = {key: value for key, value in dict.items() if key % 2 == 0}

代码3:

dict = { key: key * 10 for key in range(0, 100) }
d3 = { key: dict[key] for key in dict.keys() if key % 2 == 0}

所有代码段的性能都用timeit度量,使用number=1000,并为每段代码收集1000次。

对于python 3.6,三种过滤字典键的方式的性能几乎相同。对于python 2.7,代码3略快一些。

下面是python 2.6中的一个例子:

>>> a = {1:1, 2:2, 3:3}
>>> dict((key,value) for key, value in a.iteritems() if key == 1)
{1: 1}

过滤部分是if语句。

如果你只想选择很多键中的几个,这个方法比delnan的答案要慢。

另一个选择:

content = dict(k1='foo', k2='nope', k3='bar')
selection = ['k1', 'k3']
filtered = filter(lambda i: i[0] in selection, content.items())

但你得到的是一个列表(Python 2)或一个迭代器(Python 3),由filter()返回,而不是字典。

根据问题的标题,人们会期望在适当的地方过滤字典-几个答案建议了这样做的方法-仍然不明显的一个明显的方法是什么-我添加了一些时间:

import random
import timeit
import collections

repeat = 3
numbers = 10000

setup = ''
def timer(statement, msg='', _setup=None):
    print(msg, min(
        timeit.Timer(statement, setup=_setup or setup).repeat(
            repeat, numbers)))

timer('pass', 'Empty statement')

dsize = 1000
d = dict.fromkeys(range(dsize))
keep_keys = set(random.sample(range(dsize), 500))
drop_keys = set(random.sample(range(dsize), 500))

def _time_filter_dict():
    """filter a dict"""
    global setup
    setup = r"""from __main__ import dsize, collections, drop_keys, \
keep_keys, random"""
    timer('d = dict.fromkeys(range(dsize));'
          'collections.deque((d.pop(k) for k in drop_keys), maxlen=0)',
          "pop inplace - exhaust iterator")
    timer('d = dict.fromkeys(range(dsize));'
          'drop_keys = [k for k in d if k not in keep_keys];'
          'collections.deque('
              '(d.pop(k) for k in list(d) if k not in keep_keys), maxlen=0)',
          "pop inplace - exhaust iterator (drop_keys)")
    timer('d = dict.fromkeys(range(dsize));'
          'list(d.pop(k) for k in drop_keys)',
          "pop inplace - create list")
    timer('d = dict.fromkeys(range(dsize));'
          'drop_keys = [k for k in d if k not in keep_keys];'
          'list(d.pop(k) for k in drop_keys)',
          "pop inplace - create list (drop_keys)")
    timer('d = dict.fromkeys(range(dsize))\n'
          'for k in drop_keys: del d[k]', "del inplace")
    timer('d = dict.fromkeys(range(dsize));'
          'drop_keys = [k for k in d if k not in keep_keys]\n'
          'for k in drop_keys: del d[k]', "del inplace (drop_keys)")
    timer("""d = dict.fromkeys(range(dsize))
{k:v for k,v in d.items() if k in keep_keys}""", "copy dict comprehension")
    timer("""keep_keys=random.sample(range(dsize), 5)
d = dict.fromkeys(range(dsize))
{k:v for k,v in d.items() if k in keep_keys}""",
          "copy dict comprehension - small keep_keys")

if __name__ == '__main__':
    _time_filter_dict()

结果:

Empty statement 8.375600000000427e-05
pop inplace - exhaust iterator 1.046749841
pop inplace - exhaust iterator (drop_keys) 1.830537424
pop inplace - create list 1.1531293939999987
pop inplace - create list (drop_keys) 1.4512304149999995
del inplace 0.8008298079999996
del inplace (drop_keys) 1.1573763689999979
copy dict comprehension 1.1982901489999982
copy dict comprehension - small keep_keys 1.4407784069999998

因此,如果我们想要在适当的地方更新,似乎del是赢家-字典理解解决方案取决于正在创建的字典的大小,当然,删除一半的键已经太慢了-所以避免创建一个新的字典,如果你可以在适当的地方过滤。

编辑来解决@mpen的评论-我从keep_keys中计算了drop key(假设我们没有drop key) -我假设keep_keys/drop_keys是这个迭代的集合,或者会花很长时间。有了这些假设,del仍然更快——但要确定的是:如果你有一个(set, list, tuple)的下拉键,使用del

如果给定字典中没有一个过滤器键,则接受的答案抛出KeyError。

要获得给定字典的副本,只包含允许键中的一些键,一种方法是检查该键是否确实存在于字典推导中给定的字典中:

filtered_dict = { k: old_dict[k] for k in allowed_keys if k in old_dict }

这不会影响性能,因为对字典的查找具有恒定的运行时复杂性。

或者,您可以使用old_dict。获取(k, some_default)来填充缺失的项。