过滤字典只包含某些键?

mpe*_*pen 430 python dictionary

我有一个dict有一大堆条目.我只对他们中的一小部分感兴趣.是否有一种简单的方法可以修剪所有其他的?

小智 571

构建一个新的词典:

dict_you_want = { your_key: old_dict[your_key] for your_key in your_keys }
Run Code Online (Sandbox Code Playgroud)

使用字典理解.

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

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

就地删除所有内容:

unwanted = set(keys) - set(your_dict)
for unwanted_key in unwanted: del your_dict[unwanted_key]
Run Code Online (Sandbox Code Playgroud)

  • 不知道你也可以做dict-comprehension ...漂亮!这是一个非常好的解决方案. (17认同)
  • 如果old_dict中不存在其中一个文件管理器密钥,则抛出KeyError.如果k在d中,我会建议{k:d [k]表示过滤器中的k (7认同)
  • "使用字典理解,如果你使用缺少它们的版本"== version <= 2.6 (5认同)
  • @PeterGibson它没有,字典查找是O(1). (5认同)
  • @PeterGibson 是的,如果这是要求的一部分,您需要对其做*某事*。无论是默默地删除键,添加默认值还是其他东西,都取决于您在做什么;有很多用例你的方法是错误的。也有很多在 `old_dict` 中缺少一个键表示其他地方存在错误的情况,在这种情况下,我更喜欢错误而不是静默错误的结果。 (4认同)
  • nit:字典是哈希映射,所以正常情况是 O(1)。最坏(极不可能)的情况是 O(n),但取决于哈希冲突的可能性。你需要一个天文数字般大的字典,或者一个非常粗糙的哈希算法才能开始发现这是一个问题。/sf/answers/137446011/ (2认同)

小智 105

略微优雅的词典理解:

foodict = {k: v for k, v in mydict.items() if k.startswith('foo')}
Run Code Online (Sandbox Code Playgroud)

  • 如果使用`mydict.iteritems()`可能会是相同的性能。.items()创建另一个列表。 (4认同)
  • 回答了我自己的问题.dict中的k的{k:dict [k] ...}大约快20-25%,至少在Python 2.7.6中,有26个项目的字典(timeit(...,setup ="d = {chr(x + 97):x + 1表示x在范围内(26)}")),具体取决于过滤掉的项目数量(过滤掉辅音键比过滤掉元音键更快,因为你正在查找更少的项目).随着字典大小的增长,性能差异可能会变得不那么重要. (3认同)

jnn*_*nnn 64

这是python 2.6中的一个例子:

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

过滤部分是if声明.

如果您只想选择一些非常多的键,这种方法比delnan的答案要慢.

  • 除了我可能会使用`if key in('x','y','z')`我猜. (11认同)
  • 该解决方案还有一个优点。如果字典是从昂贵的函数调用返回的(即 a/old_dict 是函数调用),则此解决方案仅调用该函数一次。在命令式环境中,将函数返回的字典存储在变量中并不是什么大问题,但在函数式环境中(例如在 lambda 中),这是关键的观察结果。 (2认同)

Suo*_*uor 21

您可以使用我的funcy库中的项目功能执行此操作:

from funcy import project
small_dict = project(big_dict, keys)
Run Code Online (Sandbox Code Playgroud)

另请查看select_keys.


Y.Y*_*Y.Y 18

代码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
Run Code Online (Sandbox Code Playgroud)

代码2:

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

代码3:

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

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

在此输入图像描述

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

  • 最好不要使用`dict`,因为它是内置在 python 中的。 (3认同)

Jim*_*Jim 17

这个衬里lambda应该工作:

dictfilt = lambda x, y: dict([ (i,x[i]) for i in x if i in set(y) ])
Run Code Online (Sandbox Code Playgroud)

这是一个例子:

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}
Run Code Online (Sandbox Code Playgroud)

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


Kai*_*Kai 14

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

filtered = dict(zip(keys, [orig[k] for k in keys]))
Run Code Online (Sandbox Code Playgroud)

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

  • 我不反对;2.3确实不应该再存在了。然而,作为 2.3 使用情况的过时调查:http://moinmo.in/PollAboutRequiringPython24 简短版本:RHEL4、SLES9,随 OS X 10.4 一起提供 (2认同)

小智 13

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

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

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

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

Run Code Online (Sandbox Code Playgroud)


MyG*_*GaN 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'}
    
    Run Code Online (Sandbox Code Playgroud)
  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'}
    
    Run Code Online (Sandbox Code Playgroud)


Rya*_*yan 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}
Run Code Online (Sandbox Code Playgroud)

就像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}
Run Code Online (Sandbox Code Playgroud)

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

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


mar*_*rsl 6

另外一个选项:

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

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

  • 将“filtered”包裹在“dict”中,你就可以得到字典了! (6认同)

thi*_*ava 6

如果我们想制作一个删除选定键的新字典,我们可以使用字典理解
例如:

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}
Run Code Online (Sandbox Code Playgroud)


Sac*_*hin 6

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

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)
Run Code Online (Sandbox Code Playgroud)