过滤字典仅包含某些键?

问题:过滤字典仅包含某些键?

我有一个dict包含大量条目的条目。我只对其中一些感兴趣。有没有一种简单的方法可以将其他所有元素都修剪掉?

I’ve got a dict that has a whole bunch of entries. I’m only interested in a select few of them. Is there an easy way to prune all the other ones out?


回答 0

构建一个新的字典:

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]

Constructing a new dict:

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

Uses dictionary comprehension.

If you use a version which lacks them (ie Python 2.6 and earlier), make it dict((your_key, old_dict[your_key]) for ...). It’s the same, though uglier.

Note that this, unlike jnnnnn’s version, has stable performance (depends only on number of your_keys) for old_dicts of any size. Both in terms of speed and memory. Since this is a generator expression, it processes one item at a time, and it doesn’t looks through all items of old_dict.

Removing everything in-place:

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

回答 1

dict理解稍微更优雅:

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

Slightly more elegant dict comprehension:

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

回答 2

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

Here’s an example in python 2.6:

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

The filtering part is the if statement.

This method is slower than delnan’s answer if you only want to select a few of very many keys.


回答 3

您可以使用我的函数库中的项目函数来实现

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

还要看看select_keys

You can do that with project function from my funcy library:

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

Also take a look at select_keys.


回答 4

代码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随时间测量所有代码性能,并为每个代码收集1000次。

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

Code 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

Code 2:

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

Code 3:

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

All pieced of code performance are measured with timeit using number=1000, and collected 1000 times for each piece of code.

For python 3.6 the performance of three ways of filter dict keys almost the same. For python 2.7 code 3 is slightly faster.


回答 5

这一个线性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}

这是对列表键(i在x中)进行迭代的基本列表理解,如果键位于所需的键列表(y)中,则输出元组(键,值)对的列表。dict()将整个内容包装为dict对象。

This one liner lambda should work:

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

Here’s an example:

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}

It’s a basic list comprehension iterating over your dict keys (i in x) and outputs a list of tuple (key,value) pairs if the key lives in your desired key list (y). A dict() wraps the whole thing to output as a dict object.


回答 6

给定您的原始字典orig和您感兴趣的条目集keys

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

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

Given your original dictionary orig and the set of entries that you’re interested in keys:

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

which isn’t as nice as delnan’s answer, but should work in every Python version of interest. It is, however, fragile to each element of keys existing in your original dictionary.


回答 7

基于delnan接受的答案。

如果您想要的键之一不在old_dict中怎么办?delnan解决方案将引发您可以捕获的KeyError异常。如果那不是您所需要的,也许您想:

  1. 仅在old_dict和您的通缉钥匙组中包含存在的钥匙。

    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'}

Based on the accepted answer by delnan.

What if one of your wanted keys aren’t in the old_dict? The delnan solution will throw a KeyError exception that you can catch. If that’s not what you need maybe you want to:

  1. only include keys that excists both in the old_dict and your set of wanted_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. have a default value for keys that’s not set in 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

此功能可以解决问题:

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版本不同,该操作未在适当位置完成,因此性能与字典中键的数量有关。但是,这样做的好处是该函数不会修改提供的字典。

编辑:添加了一个单独的功能,用于从字典中排除某些键。

This function will do the trick:

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}

Just like delnan’s version, this one uses dictionary comprehension and has stable performance for large dictionaries (dependent only on the number of keys you permit, and not the total number of keys in the dictionary).

And just like MyGGan’s version, this one allows your list of keys to include keys that may not exist in the dictionary.

And as a bonus, here’s the inverse, where you can create a dictionary by excluding certain keys in the original:

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}

Note that unlike delnan’s version, the operation is not done in place, so the performance is related to the number of keys in the dictionary. However, the advantage of this is that the function will not modify the dictionary provided.

Edit: Added a separate function for excluding certain keys from a dict.


回答 9

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

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}

If we want to make a new dictionary with selected keys removed, we can make use of dictionary comprehension
For example:

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}

回答 10

另外一个选项:

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

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

Another option:

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

But you get a list (Python 2) or an iterator (Python 3) returned by filter(), not a dict.


回答 11

简写:

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

正如大多数答案所暗示的那样,为了保持简洁,我们必须创建一个重复的对象a list或a dict。这会产生一个一次性的东西,list但会删除original中的键dict

Short form:

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

As most of the answers suggest in order to maintain the conciseness we have to create a duplicate object be it a list or dict. This one creates a throw-away list but deletes the keys in original dict.


回答 12

这是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]

Here is another simple method using del in one liner:

for key in e_keys: del your_dict[key]

e_keys is the list of the keys to be excluded. It will update your dict rather than giving you a new one.

If you want a new output dict, then make a copy of the dict before deleting:

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

for key in e_keys: del new_dict[key]

回答 13

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

安装: 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


免责声明:我是这个图书馆的作者。

You could use python-benedict, it’s a dict subclass.

Installation: pip install python-benedict

from benedict import benedict

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

It’s open-source on GitHub: https://github.com/fabiocaccamo/python-benedict


Disclaimer: I’m the author of this library.