【问题标题】:filter items in a python dictionary where keys contain a specific string过滤python字典中的项目,其中键包含特定的字符串
【发布时间】:2014-07-14 18:31:18
【问题描述】:

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

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

即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

【问题讨论】:

标签: python python-2.7 dictionary filtering


【解决方案1】:

dict comprehension 怎么样:

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}

【讨论】:

  • 为什么不filtered_dict = {k:d[k] for k in d if filter_string in k}
  • @thefourtheye 我要猜测我的速度更快,因为它不会在d[k] 查找中进行。
  • 另外,他在 cmets 中说 # do something,但我们在此处删除了几个键。
  • 我们在 Python 3 中有 iteritems 吗?我不这么认为。所以,我的版本会兼容,不是吗?
  • 在 Python 3 中,您可以将 iteritems 替换为 items,这与 Python 2.7 的 iteritems 相同。
【解决方案2】:
input = {"A":"a", "B":"b", "C":"c"}
output = {k:v for (k,v) in input.items() if key_satifies_condition(k)}

【讨论】:

  • 我使用iteritems() 的方法将比items() 更有效。
  • @Jonathin Reinhart 我不知道。谢谢。
  • 仅在 Python 2.7 上。在 Python 3 中,只有 items(),其作用类似于 Python 2.7 的 iteritems
  • 这个问题是明确针对 python 2.7
【解决方案3】:

Jonathon 在his answer 中为您提供了一种使用字典推导的方法。这是一种处理您的做某事部分的方法。

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

我使用的是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:

>>> 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]
  • 这是正确的,但比使用map 更pythonic的是列表理解。 [f(v) for k, v in d.iteritems() if substring in k]我觉得它可读性更强,效率更高。
  • @memo 它不会接受两个参数,它会接受一个包含两个元素的参数。还有 starmap 会解压成两个参数,但是它是一个惰性迭代器(必须在执行之前进行迭代,即 results = list(starmap(...))for result in starmap(...): ...)。
【解决方案4】:

选择最易读且易于维护的内容。仅仅因为您可以将其写在一行中并不意味着您应该这样做。您现有的解决方案与我将使用的解决方案接近,除了我会使用 iteritems 来跳过值查找,如果我可以避免它们,我讨厌嵌套的 if:

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

但是,如果您真的想要一些东西来让您遍历过滤后的字典,那么我不会执行构建过滤后的字典然后遍历它的两步过程,而是使用生成器,因为更 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

简而言之:生成器很棒。

【讨论】:

    【解决方案5】:

    您可以使用内置的filter function根据特定条件过滤字典、列表等。

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

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

    【讨论】:

    • 请注意,items: 在 lambda 定义中应该是 item:
    • 感谢@bkribbs 指出错误。我现在已经改正了。
    【解决方案6】:

    您可以使用内置函数'filter()':

    data = {'aaa':12, 'bbb':23, 'ccc':8, 'ddd':34}
    
    # filter by key
    print(dict(filter(lambda e:e[0]=='bbb', data.items() ) ) )
    
    # filter by value
    print(dict(filter(lambda e:e[1]>18, data.items() ) ) )
    

    输出:

    {'bbb':23}
    
    {'bbb':23, 'ddd':34}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-05-16
      • 1970-01-01
      • 2014-07-04
      • 2020-07-16
      • 1970-01-01
      • 2019-04-11
      • 2020-06-18
      相关资源
      最近更新 更多