过滤python词典中的项,其中键包含特定的字符串


95

我是用python开发东西的C编码器。我知道如何在C语言中执行以下操作(以及因此在应用于Python的类似C的逻辑中),但是我想知道这样做的“ Python”方式是什么。

我有一个字典d,我想对项的子集进行操作,只有那些键(字符串)的项包含特定的子字符串。

即C逻辑将是:

for key in d:
    if filter_string in key:
        # do something
    else
        # do nothing, continue

我在想python版本会像

filtered_dict = crazy_python_syntax(d, substring)
for key,value in filtered_dict.iteritems():
    # do something

我在这里找到了很多有关过滤字典的文章,但是找不到与之相关的文章。

我的字典未嵌套,我正在使用python 2.7



Answers:


182

字典理解如何:

filtered_dict = {k:v for k,v in d.iteritems() if filter_string in k}

您所看到的它应该是不言自明的,因为它的英语读起来很好。

此语法要求Python 2.7或更高版本。

在Python 3中,只有dict.items()iteritems()所以您可以使用:

filtered_dict = {k:v for (k,v) in d.items() if filter_string in k}

1
为什么不filtered_dict = {k:d[k] for k in d if filter_string in k}呢?
thefourtheye 2014年

5
@thefourtheye我我的速度更快,因为它不会导致当前d[k]查询。
乔纳森·莱因哈特

此外,他# do something在评论中说,但我们在这里没有输入几个键。
thefourtheye 2014年

我们iteritems在Python 3中有吗?我不这么认为。所以,我的版本是兼容的,不是吗?
thefourtheye 2014年

1
在Python 3中,您将替换iteritemsitems,这与Python 2.7相同iteritems
Jonathon Reinhart 2014年

17

选择最易读和易于维护的内容。仅仅因为您可以将其写成一行并不意味着您应该这样做。您现有的解决方案与我将要使用的迭代器跳过用户查找值的方法很接近,并且我讨厌如果不能避免,则使用嵌套的ifs:

for key, val in d.iteritems():
    if filter_string not in key:
        continue
    # do something

但是,如果您确实想要让您迭代筛选的dict的东西,那么我将不会执行构建筛选的dict然后对其进行迭代的两步过程,而是使用生成器,因为比pythonic(和超赞的)要好得多发电机?

首先,我们创建我们的生成器,并且良好的设计要求我们使它足够抽象以便可重用:

# The implementation of my generator may look vaguely familiar, no?
def filter_dict(d, filter_string):
    for key, val in d.iteritems():
        if filter_string not in key:
            continue
        yield key, val

然后,我们可以使用生成器通过简单易懂的代码很好地,干净地解决您的问题:

for key, val in filter_dict(d, some_string):
    # do something

简而言之:发电机很棒。


10

您可以使用内置的过滤器功能根据特定条件过滤字典,列表等。

filtered_dict = dict(filter(lambda item: filter_str in item[0], d.items()))

优点是您可以将其用于不同的数据结构。


请注意,该名称items:item:在lambda定义中。
bkribbs

感谢@bkribbs指出错误。我已经纠正了。
Pulkit

8
input = {"A":"a", "B":"b", "C":"c"}
output = {k:v for (k,v) in input.items() if key_satifies_condition(k)}

3
我使用的方法iteritems()将比效率更高items()
乔纳森·莱因哈特

@Jonathin Reinhart我不知道。谢谢。
jspurim

2
仅在Python 2.7上。在Python 3中只有 items(),其作用类似于Python 2.7的iteritems
乔纳森·莱因哈特

1
这个问题明确针对python 2.7
Brendan F

7

乔纳森(Jonathon)在他的回答中给了你运用字典理解的方法。这是处理您要做的事情的一种方法。

如果您想对字典的值做一些事情,则根本不需要字典理解:

我正在使用iteritems(),因为您用标记了您的问题

results = map(some_function, [(k,v) for k,v in a_dict.iteritems() if 'foo' in k])

现在,结果将出现在列表中,该列表some_function应用于已包含foo在其键中的字典的每个键/值对。

如果只想处理值并忽略键,则只需更改列表理解即可:

results = map(some_function, [v for k,v in a_dict.iteritems() if 'foo' in k])

some_function 可以是任何可调用的,因此lambda也可以工作:

results = map(lambda x: x*2, [v for k,v in a_dict.iteritems() if 'foo' in k])

内部列表实际上不是必需的,因为您还可以传递生成器表达式来映射:

>>> map(lambda a: a[0]*a[1], ((k,v) for k,v in {2:2, 3:2}.iteritems() if k == 2))
[4]

有趣。some_function将如何定义?在第一种情况下(k,v),是否仅需要两个参数?先键然后值?
备忘录

是的,只能打电话。所以map(lambda a: a[0]*a[1], ((k,v) for k,v in {2:2, 3:2}.iteritems() if k == 2))-这会给你[4]
Burhan Khalid 2014年

这是正确的,但map列表理解比Python 具有更多的Python含义。[f(v) for k, v in d.iteritems() if substring in k]我认为它更具可读性和效率。
Davidmh,2014年

@memo它不会采用两个参数,它将采用具有两个元素的单个参数。还有一个starmap将分解为两个参数,但是它是一个惰性迭代器(必须在执行之前进行迭代,即results = list(starmap(...))or for result in starmap(...): ...)。
nmclean 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.