关于python:过滤dict以只包含某些键?

Filter dict to contain only certain keys?

我有一个dict,有很多条目。我只对其中一些感兴趣。有没有一种简单的方法可以把其他的修剪掉?


构建新的dict:

1
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 ...)。这是一样的,虽然更丑。

请注意,与Jnnnn的版本不同,这对于任何大小的old_dict都具有稳定的性能(仅取决于您的密钥数量)。无论是速度还是记忆。因为这是一个生成器表达式,所以它一次只处理一个项目,而不查看旧字典的所有项目。

移除所有东西:

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


稍微优雅一点的听写理解:

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


下面是Python2.6中的一个示例:

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

过滤部分是if语句。

如果您只想选择非常多的键中的一些,这个方法比Delnan的答案慢。


您可以使用我的Funcy库中的Project函数来完成此操作:

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

还可以看一下select_键。


这一个线性lambda应该工作:

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

下面是一个例子:

1
2
3
4
5
6
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中的i),并输出一个tuple(key,value)对列表,前提是该键位于您想要的key list(y)中。dict()将整个内容包装成dict对象输出。


鉴于您的原始词典orig和您对keys感兴趣的条目集:

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

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


代码1:

1
2
3
4
5
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:

1
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:

1
2
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次。

enter image description here

对于python3.6,三种过滤dict键的性能几乎相同。对于Python2.7,代码3稍微快一点。


此功能将实现以下功能:

1
2
3
4
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的版本一样,这个版本允许您的键列表包含字典中可能不存在的键。

作为一个额外的好处,这里是相反的,您可以通过排除原始文件中的某些键来创建字典:

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

编辑:添加了一个单独的函数,用于从dict中排除某些键。


基于德尔南接受的答案。

如果你想要的钥匙不在旧的口述里怎么办?Delnan解决方案将抛出一个可以捕获的keyError异常。如果这不是你需要的,也许你想:

  • 只包括在旧的口述和你想要的一套钥匙中都会兴奋的钥匙。

    1
    2
    3
    4
    5
    6
    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'}
  • 有一个未在旧字典中设置的键的默认值。

    1
    2
    3
    4
    5
    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'}

  • 另一种选择:

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

    但是,您会得到由filter()返回的list(python2)或迭代器(python3),而不是dict


    简短形式:

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

    正如大多数答案所建议的那样,为了保持简洁,我们必须创建一个重复的对象,无论是list还是dict。这将创建一个丢弃的list,但会删除原始dict中的密钥。