过滤字典只包含某些键?

时间:2010-08-06 00:08:37

标签: python dictionary

我有一个dict,其中包含大量条目。我只对他们中的一小部分感兴趣。有没有一种简单的方法来修剪所有其他的?

18 个答案:

答案 0 :(得分:498)

构建一个新的词典:

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

使用字典理解。

如果您使用缺少它们的版本(即Python 2.6及更早版本),请将其设为dict((your_key, old_dict[your_key]) for ...)。虽然丑陋,但它是一样的。

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

就地删除所有内容:

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

答案 1 :(得分:78)

稍微优雅的词典理解:

foodict = {k: v for k, v in mydict.items() if k.startswith('foo')}

答案 2 :(得分:63)

这是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的答案慢。

答案 3 :(得分:19)

您可以使用project库中的funcy函数执行此操作:

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

另请查看select_keys

答案 4 :(得分:16)

这个衬里lambda应该有效:

dictfilt = lambda x, y: dict([ (i,x[i]) for i in x if i in set(y) ])

以下是一个例子:

my_dict = {"a":1,"b":2,"c":3,"d":4}
wanted_keys = ("c","d")

# run it
In [10]: dictfilt(my_dict, wanted_keys)
Out[10]: {'c': 3, 'd': 4}

这是一个基本的列表理解,迭代你的dict键(我在x中)并输出一个元组(键,值)对的列表,如果键存在于你想要的键列表中(y)。 dict()将整个事物包装为输出为dict对象。

答案 5 :(得分:14)

代码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}

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

enter image description here

对于python 3.6,三种过滤器dict键的表现几乎相同。对于python 2.7代码3稍快一点。

答案 6 :(得分:13)

鉴于您的原始字典orig以及您对keys感兴趣的条目集:

filtered = dict(zip(keys, [orig[k] for k in keys]))

这不如delnan的答案那么好,但应该适用于每个感兴趣的Python版本。但是,对于原始字典中存在的keys的每个元素,它都是脆弱的。

答案 7 :(得分:6)

根据德尔南接受的答案。

如果你想要的某个密钥不在old_dict中怎么办? delnan解决方案将抛出您可以捕获的KeyError异常。如果这不是您所需要的,也许您想:

  1. 只包含在old_dict和您的want_keys集中都存在的键。

    old_dict = {'name':"Foobar", 'baz':42}
    wanted_keys = ['name', 'age']
    new_dict = {k: old_dict[k] for k in set(wanted_keys) & set(old_dict.keys())}
    
    >>> new_dict
    {'name': 'Foobar'}
    
  2. 具有未在old_dict中设置的键的默认值。

    default = None
    new_dict = {k: old_dict[k] if k in old_dict else default for k in wanted_keys}
    
    >>> new_dict
    {'age': None, 'name': 'Foobar'}
    

答案 8 :(得分:6)

这个功能可以解决问题:

def include_keys(dictionary, keys):
    """Filters a dict by only including certain keys."""
    key_set = set(keys) & set(dictionary.keys())
    return {key: dictionary[key] for key in key_set}

就像delnan的版本一样,这个版本使用字典理解并且对大型词典具有稳定的性能(仅取决于您允许的键数,而不是字典中键的总数)。

就像MyGGan的版本一样,这个版本允许您的密钥列表包含字典中可能不存在的密钥。

作为奖励,这里是反向,您可以通过排除原始中的某些键来创建字典:

def exclude_keys(dictionary, keys):
    """Filters a dict by excluding certain keys."""
    key_set = set(dictionary.keys()) - set(keys)
    return {key: dictionary[key] for key in key_set}

请注意,与delnan的版本不同,操作不会就位,因此性能与字典中的键数相关。但是,这样做的好处是该函数不会修改提供的字典。

修改:添加了一个单独的功能,用于从词典中排除某些键。

答案 9 :(得分:3)

这在我看来是最简单的方法:

d1 = {'a':1, 'b':2, 'c':3}
d2 = {k:v for k,v in d1.items() if k in ['a','c']}

我也喜欢这样做来解压值:

a, c = {k:v for k,v in d1.items() if k in ['a','c']}.values()

答案 10 :(得分:2)

您可以使用python-benedict,它是字典的子类。

安装:pip install python-benedict

from benedict import benedict

dict_you_want = benedict(your_dict).subset(keys=['firstname', 'lastname', 'email'])

它在GitHub上是开源的:https://github.com/fabiocaccamo/python-benedict


免责声明:我是该库的作者。

答案 11 :(得分:1)

简短形式:

[s.pop(k) for k in list(s.keys()) if k not in keep]

正如大多数答案所暗示的那样,为了保持简洁,我们必须创建一个重复的对象:listdict。这个会创建一个抛弃list但删除原始dict中的密钥。

答案 12 :(得分:1)

这是我的方法,支持像 mongo 查询这样的嵌套字段。

使用方法:

>>> obj = { "a":1, "b":{"c":2,"d":3}}
>>> only(obj,["a","b.c"])
{'a': 1, 'b': {'c': 2}}

only 函数:

def only(object,keys):
    obj = {}
    for path in keys:
        paths = path.split(".")
        rec=''
        origin = object
        target = obj
        for key in paths:
            rec += key
            if key in target:
                target = target[key]
                origin = origin[key]
                rec += '.'
                continue
            if key in origin:
                if rec == path:
                    target[key] = origin[key]
                else:
                    target[key] = {}
                target = target[key]
                origin = origin[key]
                rec += '.'
            else:
                target[key] = None
                break
    return obj

答案 13 :(得分:1)

如果我们要删除选定的键来制作新词典,可以利用词典理解功能
例如:

d = {
'a' : 1,
'b' : 2,
'c' : 3
}
x = {key:d[key] for key in d.keys() - {'c', 'e'}} # Python 3
y = {key:d[key] for key in set(d.keys()) - {'c', 'e'}} # Python 2.*
# x is {'a': 1, 'b': 2}
# y is {'a': 1, 'b': 2}

答案 14 :(得分:1)

另一种选择:

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

但是得到list返回的filter()(Python 2)或迭代器(Python 3),而不是dict

答案 15 :(得分:0)

这是在一个衬里中使用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]

答案 16 :(得分:0)

我们也可以通过稍微优雅的字典理解来实现这一点:

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

filtdict = {k: v for k, v in my_dict.items() if k.startswith('a')}
print(filtdict)

答案 17 :(得分:-1)

我们可以像这样简单地使用lambda函数:

>>> dict_filter = lambda x, y: dict([ (i,x[i]) for i in x if i in set(y) ])
>>> large_dict = {"a":1,"b":2,"c":3,"d":4}
>>> new_dict_keys = ("c","d")
>>> small_dict=dict_filter(large_dict, new_dict_keys)
>>> print(small_dict)
{'c': 3, 'd': 4}
>>>