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

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

我是用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

I’m a C coder developing something in python. I know how to do the following in C (and hence in C-like logic applied to python), but I’m wondering what the ‘Python’ way of doing it is.

I have a dictionary d, and I’d like to operate on a subset of the items, only those who’s key (string) contains a specific substring.

i.e. the C logic would be:

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

I’m imagining the python version would be something like

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

I’ve found a lot of posts on here regarding filtering dictionaries, but couldn’t find one which involved exactly this.

My dictionary is not nested and i’m using python 2.7


回答 0

字典理解如何:

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}

How about a dict comprehension:

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

One you see it, it should be self-explanatory, as it reads like English pretty well.

This syntax requires Python 2.7 or greater.

In Python 3, there is only dict.items(), not iteritems() so you would use:

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

回答 1

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

简而言之:生成器很棒。

Go for whatever is most readable and easily maintainable. Just because you can write it out in a single line doesn’t mean that you should. Your existing solution is close to what I would use other than I would user iteritems to skip the value lookup, and I hate nested ifs if I can avoid them:

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

However if you realllly want something to let you iterate through a filtered dict then I would not do the two step process of building the filtered dict and then iterating through it, but instead use a generator, because what is more pythonic (and awesome) than a generator?

First we create our generator, and good design dictates that we make it abstract enough to be reusable:

# 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

And then we can use the generator to solve your problem nice and cleanly with simple, understandable code:

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

In short: generators are awesome.


回答 2

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

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

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

You can use the built-in filter function to filter dictionaries, lists, etc. based on specific conditions.

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

The advantage is that you can use it for different data structures.


回答 3

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

回答 4

乔纳森(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]

Jonathon gave you an approach using dict comprehensions in his answer. Here is an approach that deals with your do something part.

If you want to do something with the values of the dictionary, you don’t need a dictionary comprehension at all:

I’m using iteritems() since you tagged your question with

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

Now the result will be in a list with some_function applied to each key/value pair of the dictionary, that has foo in its key.

If you just want to deal with the values and ignore the keys, just change the list comprehension:

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

some_function can be any callable, so a lambda would work as well:

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

The inner list is actually not required, as you can pass a generator expression to map as well:

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