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


当前回答

你可以用我的函数库中的项目函数来做:

from funcy import project
small_dict = project(big_dict, keys)

还要看一下select_keys。

其他回答

下面是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的答案要慢。

构造一个新词典:

dict_you_want = {key: old_dict[key] for key in your_keys}

使用字典理解。

如果你使用的版本缺少它们(如Python 2.6及更早版本),请将其改为dict((key, old_dict[key]) for…)。它是一样的,只是更丑。

注意,与jnnnnn版本不同的是,对于任何大小的old_dicts具有稳定的性能(仅取决于your_keys的数量)。无论是速度还是内存。因为这是一个生成器表达式,所以它一次处理一个项,并且不会查看old_dict的所有项。

把所有东西都移走:

unwanted = set(keys) - set(your_dict)
for unwanted_key in unwanted: del your_dict[unwanted_key]

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

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)来填充缺失的项。

如果你事先知道否定集(也不是键):

v = {'a': 'foo', 'b': 'bar', 'command': 'fizz', 'host': 'buzz'  }
args = {k: v[k] for k in v if k not in ["a", "b"]}
args # {'command': 'fizz', 'host': 'buzz'}